ia64/xen-unstable

view tools/libxc/xc_ptrace.c @ 7238:971e7c7411b3

Raise an exception if an error appears on the pipes to our children, and make
sure that the child's pipes are closed even under that exception. Move the
handling of POLLHUP to the end of the loop, so that we guarantee to read any
remaining data from the child if POLLHUP and POLLIN appear at the same time.

Signed-off-by: Ewan Mellor <ewan@xensource.com>
author emellor@ewan
date Thu Oct 06 10:13:11 2005 +0100 (2005-10-06)
parents 06d84bf87159
children b3a255e88810
line source
1 #include <sys/ptrace.h>
2 #include <sys/wait.h>
3 #include "xc_private.h"
4 #include "xg_private.h"
5 #include <time.h>
7 #define X86_CR0_PE 0x00000001 /* Enable Protected Mode (RW) */
8 #define X86_CR0_PG 0x80000000 /* Paging (RW) */
9 #define BSD_PAGE_MASK (PAGE_SIZE-1)
10 #define PDRSHIFT 22
11 #define PSL_T 0x00000100 /* trace enable bit */
12 #define VCPU 0 /* XXX */
14 char * ptrace_names[] = {
15 "PTRACE_TRACEME",
16 "PTRACE_PEEKTEXT",
17 "PTRACE_PEEKDATA",
18 "PTRACE_PEEKUSER",
19 "PTRACE_POKETEXT",
20 "PTRACE_POKEDATA",
21 "PTRACE_POKEUSER",
22 "PTRACE_CONT",
23 "PTRACE_KILL",
24 "PTRACE_SINGLESTEP",
25 "PTRACE_INVALID",
26 "PTRACE_INVALID",
27 "PTRACE_GETREGS",
28 "PTRACE_SETREGS",
29 "PTRACE_GETFPREGS",
30 "PTRACE_SETFPREGS",
31 "PTRACE_ATTACH",
32 "PTRACE_DETACH",
33 "PTRACE_GETFPXREGS",
34 "PTRACE_SETFPXREGS",
35 "PTRACE_INVALID",
36 "PTRACE_INVALID",
37 "PTRACE_INVALID",
38 "PTRACE_INVALID",
39 "PTRACE_SYSCALL",
40 };
42 struct gdb_regs {
43 long ebx; /* 0 */
44 long ecx; /* 4 */
45 long edx; /* 8 */
46 long esi; /* 12 */
47 long edi; /* 16 */
48 long ebp; /* 20 */
49 long eax; /* 24 */
50 int xds; /* 28 */
51 int xes; /* 32 */
52 int xfs; /* 36 */
53 int xgs; /* 40 */
54 long orig_eax; /* 44 */
55 long eip; /* 48 */
56 int xcs; /* 52 */
57 long eflags; /* 56 */
58 long esp; /* 60 */
59 int xss; /* 64 */
60 };
62 #define FETCH_REGS(cpu) \
63 if (!regs_valid[cpu]) \
64 { \
65 int retval = xc_domain_get_vcpu_context( \
66 xc_handle, domid, cpu, &ctxt[cpu]); \
67 if (retval) \
68 goto error_out; \
69 cr3[cpu] = ctxt[cpu].ctrlreg[3]; /* physical address */ \
70 regs_valid[cpu] = 1; \
71 }
73 #define printval(x) printf("%s = %lx\n", #x, (long)x);
74 #define SET_PT_REGS(pt, xc) \
75 { \
76 pt.ebx = xc.ebx; \
77 pt.ecx = xc.ecx; \
78 pt.edx = xc.edx; \
79 pt.esi = xc.esi; \
80 pt.edi = xc.edi; \
81 pt.ebp = xc.ebp; \
82 pt.eax = xc.eax; \
83 pt.eip = xc.eip; \
84 pt.xcs = xc.cs; \
85 pt.eflags = xc.eflags; \
86 pt.esp = xc.esp; \
87 pt.xss = xc.ss; \
88 pt.xes = xc.es; \
89 pt.xds = xc.ds; \
90 pt.xfs = xc.fs; \
91 pt.xgs = xc.gs; \
92 }
94 #define SET_XC_REGS(pt, xc) \
95 { \
96 xc.ebx = pt->ebx; \
97 xc.ecx = pt->ecx; \
98 xc.edx = pt->edx; \
99 xc.esi = pt->esi; \
100 xc.edi = pt->edi; \
101 xc.ebp = pt->ebp; \
102 xc.eax = pt->eax; \
103 xc.eip = pt->eip; \
104 xc.cs = pt->xcs; \
105 xc.eflags = pt->eflags; \
106 xc.esp = pt->esp; \
107 xc.ss = pt->xss; \
108 xc.es = pt->xes; \
109 xc.ds = pt->xds; \
110 xc.fs = pt->xfs; \
111 xc.gs = pt->xgs; \
112 }
114 #define vtopdi(va) ((va) >> PDRSHIFT)
115 #define vtopti(va) (((va) >> PAGE_SHIFT) & 0x3ff)
117 /* XXX application state */
118 static long nr_pages = 0;
119 unsigned long *page_array = NULL;
120 static int regs_valid[MAX_VIRT_CPUS];
121 static unsigned long cr3[MAX_VIRT_CPUS];
122 static vcpu_guest_context_t ctxt[MAX_VIRT_CPUS];
124 static inline int paging_enabled(vcpu_guest_context_t *v)
125 {
126 unsigned long cr0 = v->ctrlreg[0];
127 return (cr0 & X86_CR0_PE) && (cr0 & X86_CR0_PG);
128 }
130 /* --------------------- */
132 static void *
133 map_domain_va_pae(
134 int xc_handle,
135 unsigned long domid,
136 int cpu,
137 void *guest_va,
138 int perm)
139 {
140 unsigned long l2p, l1p, p, va = (unsigned long)guest_va;
141 u64 *l3, *l2, *l1;
142 static void *v;
144 FETCH_REGS(cpu);
146 l3 = xc_map_foreign_range(
147 xc_handle, domid, PAGE_SIZE, PROT_READ, cr3[cpu] >> PAGE_SHIFT);
148 if ( l3 == NULL )
149 goto error_out;
151 l2p = l3[l3_table_offset_pae(va)] >> PAGE_SHIFT;
152 l2 = xc_map_foreign_range(xc_handle, domid, PAGE_SIZE, PROT_READ, l2p);
153 if ( l2 == NULL )
154 goto error_out;
156 l1p = l2[l2_table_offset_pae(va)] >> PAGE_SHIFT;
157 l1 = xc_map_foreign_range(xc_handle, domid, PAGE_SIZE, perm, l1p);
158 if ( l1 == NULL )
159 goto error_out;
161 p = l1[l1_table_offset_pae(va)] >> PAGE_SHIFT;
162 if ( v != NULL )
163 munmap(v, PAGE_SIZE);
164 v = xc_map_foreign_range(xc_handle, domid, PAGE_SIZE, perm, p);
165 if ( v == NULL )
166 goto error_out;
168 return (void *)((unsigned long)v | (va & (PAGE_SIZE - 1)));
170 error_out:
171 return NULL;
172 }
174 static void *
175 map_domain_va(
176 int xc_handle,
177 unsigned long domid,
178 int cpu,
179 void *guest_va,
180 int perm)
181 {
182 unsigned long pde, page;
183 unsigned long va = (unsigned long)guest_va;
184 long npgs = xc_get_tot_pages(xc_handle, domid);
186 static unsigned long cr3_phys[MAX_VIRT_CPUS];
187 static unsigned long *cr3_virt[MAX_VIRT_CPUS];
188 static unsigned long pde_phys[MAX_VIRT_CPUS];
189 static unsigned long *pde_virt[MAX_VIRT_CPUS];
190 static unsigned long page_phys[MAX_VIRT_CPUS];
191 static unsigned long *page_virt[MAX_VIRT_CPUS];
192 static int prev_perm[MAX_VIRT_CPUS];
193 static enum { MODE_UNKNOWN, MODE_32, MODE_PAE } mode;
195 if ( mode == MODE_UNKNOWN )
196 {
197 xen_capabilities_info_t caps;
198 (void)xc_version(xc_handle, XENVER_capabilities, caps);
199 mode = MODE_32;
200 if ( strstr(caps, "_x86_32p") )
201 mode = MODE_PAE;
202 }
204 if ( mode == MODE_PAE )
205 return map_domain_va_pae(xc_handle, domid, cpu, guest_va, perm);
207 if ( nr_pages != npgs )
208 {
209 if ( nr_pages > 0 )
210 free(page_array);
211 nr_pages = npgs;
212 if ( (page_array = malloc(nr_pages * sizeof(unsigned long))) == NULL )
213 {
214 printf("Could not allocate memory\n");
215 goto error_out;
216 }
217 if ( xc_get_pfn_list(xc_handle, domid,
218 page_array, nr_pages) != nr_pages )
219 {
220 printf("Could not get the page frame list\n");
221 goto error_out;
222 }
223 }
225 FETCH_REGS(cpu);
227 if ( cr3[cpu] != cr3_phys[cpu] )
228 {
229 cr3_phys[cpu] = cr3[cpu];
230 if ( cr3_virt[cpu] )
231 munmap(cr3_virt[cpu], PAGE_SIZE);
232 cr3_virt[cpu] = xc_map_foreign_range(
233 xc_handle, domid, PAGE_SIZE, PROT_READ,
234 cr3_phys[cpu] >> PAGE_SHIFT);
235 if ( cr3_virt[cpu] == NULL )
236 goto error_out;
237 }
238 if ( (pde = cr3_virt[cpu][vtopdi(va)]) == 0 )
239 goto error_out;
240 if ( (ctxt[cpu].flags & VGCF_VMX_GUEST) && paging_enabled(&ctxt[cpu]) )
241 pde = page_array[pde >> PAGE_SHIFT] << PAGE_SHIFT;
242 if ( pde != pde_phys[cpu] )
243 {
244 pde_phys[cpu] = pde;
245 if ( pde_virt[cpu] )
246 munmap(pde_virt[cpu], PAGE_SIZE);
247 pde_virt[cpu] = xc_map_foreign_range(
248 xc_handle, domid, PAGE_SIZE, PROT_READ,
249 pde_phys[cpu] >> PAGE_SHIFT);
250 if ( pde_virt[cpu] == NULL )
251 goto error_out;
252 }
253 if ( (page = pde_virt[cpu][vtopti(va)]) == 0 )
254 goto error_out;
255 if ( (ctxt[cpu].flags & VGCF_VMX_GUEST) && paging_enabled(&ctxt[cpu]) )
256 page = page_array[page >> PAGE_SHIFT] << PAGE_SHIFT;
257 if ( (page != page_phys[cpu]) || (perm != prev_perm[cpu]) )
258 {
259 page_phys[cpu] = page;
260 if ( page_virt[cpu] )
261 munmap(page_virt[cpu], PAGE_SIZE);
262 page_virt[cpu] = xc_map_foreign_range(
263 xc_handle, domid, PAGE_SIZE, perm,
264 page_phys[cpu] >> PAGE_SHIFT);
265 if ( page_virt[cpu] == NULL )
266 {
267 page_phys[cpu] = 0;
268 goto error_out;
269 }
270 prev_perm[cpu] = perm;
271 }
273 return (void *)(((unsigned long)page_virt[cpu]) | (va & BSD_PAGE_MASK));
275 error_out:
276 return NULL;
277 }
279 int
280 xc_waitdomain(
281 int xc_handle,
282 int domain,
283 int *status,
284 int options)
285 {
286 dom0_op_t op;
287 int retval;
288 struct timespec ts;
289 ts.tv_sec = 0;
290 ts.tv_nsec = 10*1000*1000;
292 op.cmd = DOM0_GETDOMAININFO;
293 op.u.getdomaininfo.domain = domain;
295 retry:
296 retval = do_dom0_op(xc_handle, &op);
297 if ( retval || (op.u.getdomaininfo.domain != domain) )
298 {
299 printf("getdomaininfo failed\n");
300 goto done;
301 }
302 *status = op.u.getdomaininfo.flags;
304 if ( options & WNOHANG )
305 goto done;
307 if ( !(op.u.getdomaininfo.flags & DOMFLAGS_PAUSED) )
308 {
309 nanosleep(&ts,NULL);
310 goto retry;
311 }
313 done:
314 return retval;
316 }
318 long
319 xc_ptrace(
320 int xc_handle,
321 enum __ptrace_request request,
322 u32 domid,
323 long eaddr,
324 long edata)
325 {
326 dom0_op_t op;
327 int status = 0;
328 struct gdb_regs pt;
329 long retval = 0;
330 unsigned long *guest_va;
331 int cpu = VCPU;
332 void *addr = (char *)eaddr;
333 void *data = (char *)edata;
335 op.interface_version = DOM0_INTERFACE_VERSION;
337 switch ( request )
338 {
339 case PTRACE_PEEKTEXT:
340 case PTRACE_PEEKDATA:
341 guest_va = (unsigned long *)map_domain_va(
342 xc_handle, domid, cpu, addr, PROT_READ);
343 if ( guest_va == NULL )
344 {
345 status = EFAULT;
346 goto error_out;
347 }
348 retval = *guest_va;
349 break;
351 case PTRACE_POKETEXT:
352 case PTRACE_POKEDATA:
353 guest_va = (unsigned long *)map_domain_va(
354 xc_handle, domid, cpu, addr, PROT_READ|PROT_WRITE);
355 if ( guest_va == NULL )
356 {
357 status = EFAULT;
358 goto error_out;
359 }
360 *guest_va = (unsigned long)data;
361 break;
363 case PTRACE_GETREGS:
364 case PTRACE_GETFPREGS:
365 case PTRACE_GETFPXREGS:
366 FETCH_REGS(cpu);
367 if ( request == PTRACE_GETREGS )
368 {
369 SET_PT_REGS(pt, ctxt[cpu].user_regs);
370 memcpy(data, &pt, sizeof(struct gdb_regs));
371 }
372 else if (request == PTRACE_GETFPREGS)
373 {
374 memcpy(data, &ctxt[cpu].fpu_ctxt, sizeof(ctxt[cpu].fpu_ctxt));
375 }
376 else /*if (request == PTRACE_GETFPXREGS)*/
377 {
378 memcpy(data, &ctxt[cpu].fpu_ctxt, sizeof(ctxt[cpu].fpu_ctxt));
379 }
380 break;
382 case PTRACE_SETREGS:
383 op.cmd = DOM0_SETDOMAININFO;
384 SET_XC_REGS(((struct gdb_regs *)data), ctxt[VCPU].user_regs);
385 op.u.setdomaininfo.domain = domid;
386 /* XXX need to understand multiple vcpus */
387 op.u.setdomaininfo.vcpu = cpu;
388 op.u.setdomaininfo.ctxt = &ctxt[cpu];
389 retval = do_dom0_op(xc_handle, &op);
390 if (retval)
391 goto error_out;
392 break;
394 case PTRACE_ATTACH:
395 op.cmd = DOM0_GETDOMAININFO;
396 op.u.getdomaininfo.domain = domid;
397 retval = do_dom0_op(xc_handle, &op);
398 if ( retval || (op.u.getdomaininfo.domain != domid) )
399 {
400 perror("dom0 op failed");
401 goto error_out;
402 }
403 if ( op.u.getdomaininfo.flags & DOMFLAGS_PAUSED )
404 {
405 printf("domain currently paused\n");
406 goto error_out;
407 }
408 printf("domain not currently paused\n");
409 op.cmd = DOM0_PAUSEDOMAIN;
410 op.u.pausedomain.domain = domid;
411 retval = do_dom0_op(xc_handle, &op);
412 break;
414 case PTRACE_SINGLESTEP:
415 ctxt[VCPU].user_regs.eflags |= PSL_T;
416 op.cmd = DOM0_SETDOMAININFO;
417 op.u.setdomaininfo.domain = domid;
418 op.u.setdomaininfo.vcpu = 0;
419 op.u.setdomaininfo.ctxt = &ctxt[cpu];
420 retval = do_dom0_op(xc_handle, &op);
421 if ( retval )
422 {
423 perror("dom0 op failed");
424 goto error_out;
425 }
426 /* FALLTHROUGH */
428 case PTRACE_CONT:
429 case PTRACE_DETACH:
430 if ( request != PTRACE_SINGLESTEP )
431 {
432 FETCH_REGS(cpu);
433 /* Clear trace flag */
434 if ( ctxt[cpu].user_regs.eflags & PSL_T )
435 {
436 ctxt[cpu].user_regs.eflags &= ~PSL_T;
437 op.cmd = DOM0_SETDOMAININFO;
438 op.u.setdomaininfo.domain = domid;
439 op.u.setdomaininfo.vcpu = cpu;
440 op.u.setdomaininfo.ctxt = &ctxt[cpu];
441 retval = do_dom0_op(xc_handle, &op);
442 if ( retval )
443 {
444 perror("dom0 op failed");
445 goto error_out;
446 }
447 }
448 }
449 regs_valid[cpu] = 0;
450 op.cmd = DOM0_UNPAUSEDOMAIN;
451 op.u.unpausedomain.domain = domid > 0 ? domid : -domid;
452 retval = do_dom0_op(xc_handle, &op);
453 break;
455 case PTRACE_SETFPREGS:
456 case PTRACE_SETFPXREGS:
457 case PTRACE_PEEKUSER:
458 case PTRACE_POKEUSER:
459 case PTRACE_SYSCALL:
460 case PTRACE_KILL:
461 #ifdef DEBUG
462 printf("unsupported xc_ptrace request %s\n", ptrace_names[request]);
463 #endif
464 /* XXX not yet supported */
465 status = ENOSYS;
466 break;
468 case PTRACE_TRACEME:
469 printf("PTRACE_TRACEME is an invalid request under Xen\n");
470 status = EINVAL;
471 }
473 if ( status )
474 {
475 errno = status;
476 retval = -1;
477 }
479 error_out:
480 return retval;
481 }
483 /*
484 * Local variables:
485 * mode: C
486 * c-set-style: "BSD"
487 * c-basic-offset: 4
488 * tab-width: 4
489 * indent-tabs-mode: nil
490 * End:
491 */