ia64/xen-unstable

view tools/libxc/xc_ptrace.c @ 6141:7c2fdcb2c933

another merge
author kaf24@firebug.cl.cam.ac.uk
date Fri Aug 12 14:53:26 2005 +0000 (2005-08-12)
parents 38bee85ddeb8 1fb1877ed6d1
children 4995d5f167c9 f51fe43c5d1c 6783e59e1c45
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 }