ia64/xen-unstable

view tools/libxc/xc_ptrace.c @ 8964:8946b6dcd49e

Fix x86_64 Xen build.

event_callback_cs and failsafe_callback_cs are x86_32 only.

Signed-off-by: Ian Campbell <Ian.Campbell@XenSource.com>
author Ian.Campbell@xensource.com
date Wed Feb 22 17:26:39 2006 +0000 (2006-02-22)
parents f1b361b05bf3
children 26eff2448966
line source
1 #define XC_PTRACE_PRIVATE
4 #include <sys/ptrace.h>
5 #include <sys/wait.h>
6 #include <time.h>
8 #include "xc_private.h"
9 #include "xg_private.h"
10 #include <thread_db.h>
11 #include "xc_ptrace.h"
14 /* XXX application state */
15 static long nr_pages = 0;
16 static unsigned long *page_array = NULL;
17 static int current_domid = -1;
19 static cpumap_t online_cpumap;
20 static cpumap_t regs_valid;
21 static vcpu_guest_context_t ctxt[MAX_VIRT_CPUS];
23 extern int ffsll(long long int);
24 #define FOREACH_CPU(cpumap, i) for ( cpumap = online_cpumap; (i = ffsll(cpumap)); cpumap &= ~(1 << (index - 1)) )
27 static int
28 fetch_regs(int xc_handle, int cpu, int *online)
29 {
30 xc_vcpuinfo_t info;
31 int retval = 0;
33 if (online)
34 *online = 0;
35 if ( !(regs_valid & (1 << cpu)) ) {
36 retval = xc_vcpu_getcontext(xc_handle, current_domid,
37 cpu, &ctxt[cpu]);
38 if ( retval )
39 goto done;
40 regs_valid |= (1 << cpu);
42 }
43 if ( online == NULL )
44 goto done;
46 retval = xc_vcpu_getinfo(xc_handle, current_domid, cpu, &info);
47 *online = info.online;
49 done:
50 return retval;
51 }
53 #define FETCH_REGS(cpu) if (fetch_regs(xc_handle, cpu, NULL)) goto error_out;
56 static struct thr_ev_handlers {
57 thr_ev_handler_t td_create;
58 thr_ev_handler_t td_death;
59 } handlers;
61 void
62 xc_register_event_handler(thr_ev_handler_t h,
63 td_event_e e)
64 {
65 switch (e) {
66 case TD_CREATE:
67 handlers.td_create = h;
68 break;
69 case TD_DEATH:
70 handlers.td_death = h;
71 break;
72 default:
73 abort(); /* XXX */
74 }
75 }
77 static inline int
78 paging_enabled(vcpu_guest_context_t *v)
79 {
80 unsigned long cr0 = v->ctrlreg[0];
81 return (cr0 & X86_CR0_PE) && (cr0 & X86_CR0_PG);
82 }
84 /*
85 * Fetch registers for all online cpus and set the cpumap
86 * to indicate which cpus are online
87 *
88 */
90 static int
91 get_online_cpumap(int xc_handle, dom0_getdomaininfo_t *d, cpumap_t *cpumap)
92 {
93 int i, online, retval;
95 *cpumap = 0;
96 for (i = 0; i <= d->max_vcpu_id; i++) {
97 if ((retval = fetch_regs(xc_handle, i, &online)))
98 goto error_out;
99 if (online)
100 *cpumap |= (1 << i);
101 }
103 return 0;
104 error_out:
105 return retval;
106 }
108 /*
109 * Notify GDB of any vcpus that have come online or gone offline
110 * update online_cpumap
111 *
112 */
114 static void
115 online_vcpus_changed(cpumap_t cpumap)
116 {
117 cpumap_t changed_cpumap = cpumap ^ online_cpumap;
118 int index;
120 while ( (index = ffsll(changed_cpumap)) ) {
121 if ( cpumap & (1 << (index - 1)) ) {
122 if (handlers.td_create) handlers.td_create(index - 1);
123 } else {
124 printf("thread death: %d\n", index - 1);
125 if (handlers.td_death) handlers.td_death(index - 1);
126 }
127 changed_cpumap &= ~(1 << (index - 1));
128 }
129 online_cpumap = cpumap;
131 }
133 /* --------------------- */
135 static void *
136 map_domain_va_pae(
137 int xc_handle,
138 int cpu,
139 void *guest_va,
140 int perm)
141 {
142 unsigned long l2p, l1p, p, va = (unsigned long)guest_va;
143 uint64_t *l3, *l2, *l1;
144 static void *v;
146 FETCH_REGS(cpu);
148 l3 = xc_map_foreign_range(
149 xc_handle, current_domid, PAGE_SIZE, PROT_READ, ctxt[cpu].ctrlreg[3] >> PAGE_SHIFT);
150 if ( l3 == NULL )
151 goto error_out;
153 l2p = l3[l3_table_offset_pae(va)] >> PAGE_SHIFT;
154 l2 = xc_map_foreign_range(xc_handle, current_domid, PAGE_SIZE, PROT_READ, l2p);
155 if ( l2 == NULL )
156 goto error_out;
158 l1p = l2[l2_table_offset_pae(va)] >> PAGE_SHIFT;
159 l1 = xc_map_foreign_range(xc_handle, current_domid, PAGE_SIZE, perm, l1p);
160 if ( l1 == NULL )
161 goto error_out;
163 p = l1[l1_table_offset_pae(va)] >> PAGE_SHIFT;
164 if ( v != NULL )
165 munmap(v, PAGE_SIZE);
166 v = xc_map_foreign_range(xc_handle, current_domid, PAGE_SIZE, perm, p);
167 if ( v == NULL )
168 goto error_out;
170 return (void *)((unsigned long)v | (va & (PAGE_SIZE - 1)));
172 error_out:
173 return NULL;
174 }
176 static void *
177 map_domain_va(
178 int xc_handle,
179 int cpu,
180 void *guest_va,
181 int perm)
182 {
184 unsigned long pde, page;
185 unsigned long va = (unsigned long)guest_va;
186 long npgs = xc_get_tot_pages(xc_handle, current_domid);
189 static uint32_t cr3_phys[MAX_VIRT_CPUS];
190 static unsigned long *cr3_virt[MAX_VIRT_CPUS];
191 static unsigned long pde_phys[MAX_VIRT_CPUS];
192 static unsigned long *pde_virt[MAX_VIRT_CPUS];
193 static unsigned long page_phys[MAX_VIRT_CPUS];
194 static unsigned long *page_virt[MAX_VIRT_CPUS];
195 static int prev_perm[MAX_VIRT_CPUS];
196 static enum { MODE_UNKNOWN, MODE_32, MODE_PAE } mode;
198 if ( mode == MODE_UNKNOWN )
199 {
200 xen_capabilities_info_t caps;
201 (void)xc_version(xc_handle, XENVER_capabilities, caps);
202 mode = MODE_32;
203 if ( strstr(caps, "_x86_32p") )
204 mode = MODE_PAE;
205 }
207 if ( mode == MODE_PAE )
208 return map_domain_va_pae(xc_handle, cpu, guest_va, perm);
210 if ( nr_pages != npgs )
211 {
212 if ( nr_pages > 0 )
213 free(page_array);
214 nr_pages = npgs;
215 if ( (page_array = malloc(nr_pages * sizeof(unsigned long))) == NULL )
216 {
217 printf("Could not allocate memory\n");
218 goto error_out;
219 }
220 if ( xc_get_pfn_list(xc_handle, current_domid,
221 page_array, nr_pages) != nr_pages )
222 {
223 printf("Could not get the page frame list\n");
224 goto error_out;
225 }
226 }
228 FETCH_REGS(cpu);
230 if ( ctxt[cpu].ctrlreg[3] != cr3_phys[cpu] )
231 {
232 cr3_phys[cpu] = ctxt[cpu].ctrlreg[3];
233 if ( cr3_virt[cpu] )
234 munmap(cr3_virt[cpu], PAGE_SIZE);
235 cr3_virt[cpu] = xc_map_foreign_range(
236 xc_handle, current_domid, PAGE_SIZE, PROT_READ,
237 cr3_phys[cpu] >> PAGE_SHIFT);
238 if ( cr3_virt[cpu] == NULL )
239 goto error_out;
240 }
241 if ( (pde = cr3_virt[cpu][vtopdi(va)]) == 0 )
242 goto error_out;
243 if ( (ctxt[cpu].flags & VGCF_HVM_GUEST) && paging_enabled(&ctxt[cpu]) )
244 pde = page_array[pde >> PAGE_SHIFT] << PAGE_SHIFT;
245 if ( pde != pde_phys[cpu] )
246 {
247 pde_phys[cpu] = pde;
248 if ( pde_virt[cpu] )
249 munmap(pde_virt[cpu], PAGE_SIZE);
250 pde_virt[cpu] = xc_map_foreign_range(
251 xc_handle, current_domid, PAGE_SIZE, PROT_READ,
252 pde_phys[cpu] >> PAGE_SHIFT);
253 if ( pde_virt[cpu] == NULL )
254 goto error_out;
255 }
256 if ( (page = pde_virt[cpu][vtopti(va)]) == 0 )
257 goto error_out;
258 if ( (ctxt[cpu].flags & VGCF_HVM_GUEST) && paging_enabled(&ctxt[cpu]) )
259 page = page_array[page >> PAGE_SHIFT] << PAGE_SHIFT;
260 if ( (page != page_phys[cpu]) || (perm != prev_perm[cpu]) )
261 {
262 page_phys[cpu] = page;
263 if ( page_virt[cpu] )
264 munmap(page_virt[cpu], PAGE_SIZE);
265 page_virt[cpu] = xc_map_foreign_range(
266 xc_handle, current_domid, PAGE_SIZE, perm,
267 page_phys[cpu] >> PAGE_SHIFT);
268 if ( page_virt[cpu] == NULL )
269 {
270 page_phys[cpu] = 0;
271 goto error_out;
272 }
273 prev_perm[cpu] = perm;
274 }
276 return (void *)(((unsigned long)page_virt[cpu]) | (va & BSD_PAGE_MASK));
278 error_out:
279 return NULL;
280 }
282 int
283 xc_waitdomain(
284 int xc_handle,
285 int domain,
286 int *status,
287 int options)
288 {
289 DECLARE_DOM0_OP;
290 int retval;
291 struct timespec ts;
292 cpumap_t cpumap;
294 ts.tv_sec = 0;
295 ts.tv_nsec = 10*1000*1000;
297 op.cmd = DOM0_GETDOMAININFO;
298 op.u.getdomaininfo.domain = domain;
301 retry:
302 retval = do_dom0_op(xc_handle, &op);
303 if ( retval || (op.u.getdomaininfo.domain != domain) )
304 {
305 printf("getdomaininfo failed\n");
306 goto done;
307 }
308 *status = op.u.getdomaininfo.flags;
310 if ( options & WNOHANG )
311 goto done;
313 if ( !(op.u.getdomaininfo.flags & DOMFLAGS_PAUSED) )
314 {
315 nanosleep(&ts,NULL);
316 goto retry;
317 }
318 /* XXX check for ^C here */
319 done:
320 if (get_online_cpumap(xc_handle, &op.u.getdomaininfo, &cpumap))
321 printf("get_online_cpumap failed\n");
322 if (online_cpumap != cpumap)
323 online_vcpus_changed(cpumap);
324 return retval;
326 }
329 long
330 xc_ptrace(
331 int xc_handle,
332 enum __ptrace_request request,
333 uint32_t domid_tid,
334 long eaddr,
335 long edata)
336 {
337 DECLARE_DOM0_OP;
338 int status = 0;
339 struct gdb_regs pt;
340 long retval = 0;
341 unsigned long *guest_va;
342 cpumap_t cpumap;
343 int cpu, index;
344 void *addr = (char *)eaddr;
345 void *data = (char *)edata;
347 cpu = (request != PTRACE_ATTACH) ? domid_tid : 0;
349 switch ( request )
350 {
351 case PTRACE_PEEKTEXT:
352 case PTRACE_PEEKDATA:
353 guest_va = (unsigned long *)map_domain_va(
354 xc_handle, cpu, addr, PROT_READ);
355 if ( guest_va == NULL )
356 {
357 status = EFAULT;
358 goto error_out;
359 }
360 retval = *guest_va;
361 break;
363 case PTRACE_POKETEXT:
364 case PTRACE_POKEDATA:
365 /* XXX assume that all CPUs have the same address space */
366 guest_va = (unsigned long *)map_domain_va(
367 xc_handle, cpu, addr, PROT_READ|PROT_WRITE);
368 if ( guest_va == NULL ) {
369 status = EFAULT;
370 goto error_out;
371 }
372 *guest_va = (unsigned long)data;
373 break;
375 case PTRACE_GETREGS:
376 case PTRACE_GETFPREGS:
377 case PTRACE_GETFPXREGS:
379 FETCH_REGS(cpu);
380 if ( request == PTRACE_GETREGS )
381 {
382 SET_PT_REGS(pt, ctxt[cpu].user_regs);
383 memcpy(data, &pt, sizeof(struct gdb_regs));
384 }
385 else if (request == PTRACE_GETFPREGS)
386 {
387 memcpy(data, &ctxt[cpu].fpu_ctxt, sizeof(ctxt[cpu].fpu_ctxt));
388 }
389 else /*if (request == PTRACE_GETFPXREGS)*/
390 {
391 memcpy(data, &ctxt[cpu].fpu_ctxt, sizeof(ctxt[cpu].fpu_ctxt));
392 }
393 break;
395 case PTRACE_SETREGS:
396 SET_XC_REGS(((struct gdb_regs *)data), ctxt[cpu].user_regs);
397 retval = xc_vcpu_setcontext(xc_handle, current_domid, cpu, &ctxt[cpu]);
398 if (retval)
399 goto error_out;
400 break;
402 case PTRACE_SINGLESTEP:
403 /* XXX we can still have problems if the user switches threads
404 * during single-stepping - but that just seems retarded
405 */
406 ctxt[cpu].user_regs.eflags |= PSL_T;
407 retval = xc_vcpu_setcontext(xc_handle, current_domid, cpu, &ctxt[cpu]);
408 if ( retval )
409 {
410 perror("dom0 op failed");
411 goto error_out;
412 }
413 /* FALLTHROUGH */
415 case PTRACE_CONT:
416 case PTRACE_DETACH:
417 if ( request != PTRACE_SINGLESTEP )
418 {
419 FOREACH_CPU(cpumap, index) {
420 cpu = index - 1;
421 FETCH_REGS(cpu);
422 /* Clear trace flag */
423 if ( ctxt[cpu].user_regs.eflags & PSL_T ) {
424 ctxt[cpu].user_regs.eflags &= ~PSL_T;
425 retval = xc_vcpu_setcontext(xc_handle, current_domid,
426 cpu, &ctxt[cpu]);
427 if ( retval ) {
428 perror("dom0 op failed");
429 goto error_out;
430 }
431 }
432 }
433 }
434 if ( request == PTRACE_DETACH )
435 {
436 op.cmd = DOM0_SETDEBUGGING;
437 op.u.setdebugging.domain = current_domid;
438 op.u.setdebugging.enable = 0;
439 retval = do_dom0_op(xc_handle, &op);
440 }
441 regs_valid = 0;
442 xc_domain_unpause(xc_handle, current_domid > 0 ? current_domid : -current_domid);
443 break;
445 case PTRACE_ATTACH:
446 current_domid = domid_tid;
447 op.cmd = DOM0_GETDOMAININFO;
448 op.u.getdomaininfo.domain = current_domid;
449 retval = do_dom0_op(xc_handle, &op);
450 if ( retval || (op.u.getdomaininfo.domain != current_domid) )
451 {
452 perror("dom0 op failed");
453 goto error_out;
454 }
455 if ( op.u.getdomaininfo.flags & DOMFLAGS_PAUSED )
456 {
457 printf("domain currently paused\n");
458 } else
459 retval = xc_domain_pause(xc_handle, current_domid);
460 op.cmd = DOM0_SETDEBUGGING;
461 op.u.setdebugging.domain = current_domid;
462 op.u.setdebugging.enable = 1;
463 retval = do_dom0_op(xc_handle, &op);
465 if (get_online_cpumap(xc_handle, &op.u.getdomaininfo, &cpumap))
466 printf("get_online_cpumap failed\n");
467 if (online_cpumap != cpumap)
468 online_vcpus_changed(cpumap);
469 break;
471 case PTRACE_SETFPREGS:
472 case PTRACE_SETFPXREGS:
473 case PTRACE_PEEKUSER:
474 case PTRACE_POKEUSER:
475 case PTRACE_SYSCALL:
476 case PTRACE_KILL:
477 #ifdef DEBUG
478 printf("unsupported xc_ptrace request %s\n", ptrace_names[request]);
479 #endif
480 /* XXX not yet supported */
481 status = ENOSYS;
482 break;
484 case PTRACE_TRACEME:
485 printf("PTRACE_TRACEME is an invalid request under Xen\n");
486 status = EINVAL;
487 }
489 if ( status )
490 {
491 errno = status;
492 retval = -1;
493 }
495 error_out:
496 return retval;
497 }
499 /*
500 * Local variables:
501 * mode: C
502 * c-set-style: "BSD"
503 * c-basic-offset: 4
504 * tab-width: 4
505 * indent-tabs-mode: nil
506 * End:
507 */