File: | obj-scan-build/../i386/i386/db_interface.c |
Location: | line 342, column 1 |
Description: | Address of stack memory associated with local variable 'type' is still referred to by the global variable 'i386_last_kdb_sp' upon returning to the caller. This will be a dangling reference |
1 | /* | |||
2 | * Mach Operating System | |||
3 | * Copyright (c) 1993,1992,1991,1990 Carnegie Mellon University | |||
4 | * All Rights Reserved. | |||
5 | * | |||
6 | * Permission to use, copy, modify and distribute this software and its | |||
7 | * documentation is hereby granted, provided that both the copyright | |||
8 | * notice and this permission notice appear in all copies of the | |||
9 | * software, derivative works or modified versions, and any portions | |||
10 | * thereof, and that both notices appear in supporting documentation. | |||
11 | * | |||
12 | * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" | |||
13 | * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR | |||
14 | * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. | |||
15 | * | |||
16 | * Carnegie Mellon requests users of this software to return to | |||
17 | * | |||
18 | * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU | |||
19 | * School of Computer Science | |||
20 | * Carnegie Mellon University | |||
21 | * Pittsburgh PA 15213-3890 | |||
22 | * | |||
23 | * any improvements or extensions that they make and grant Carnegie Mellon | |||
24 | * the rights to redistribute these changes. | |||
25 | */ | |||
26 | /* | |||
27 | * Interface to new debugger. | |||
28 | */ | |||
29 | ||||
30 | #include <string.h> | |||
31 | #include <sys/reboot.h> | |||
32 | #include <vm/pmap.h> | |||
33 | ||||
34 | #include <i3861/thread.h> | |||
35 | #include <i3861/db_machdep.h> | |||
36 | #include <i3861/seg.h> | |||
37 | #include <i3861/trap.h> | |||
38 | #include <i3861/setjmp.h> | |||
39 | #include <i3861/pmap.h> | |||
40 | #include <i3861/proc_reg.h> | |||
41 | #include <i3861/locore.h> | |||
42 | #include "gdt.h" | |||
43 | #include "trap.h" | |||
44 | ||||
45 | #include "vm_param.h" | |||
46 | #include <vm/vm_map.h> | |||
47 | #include <vm/vm_fault.h> | |||
48 | #include <kern/cpu_number.h> | |||
49 | #include <kern/printf.h> | |||
50 | #include <kern/thread.h> | |||
51 | #include <kern/task.h> | |||
52 | #include <ddb/db_access.h> | |||
53 | #include <ddb/db_command.h> | |||
54 | #include <ddb/db_output.h> | |||
55 | #include <ddb/db_run.h> | |||
56 | #include <ddb/db_task_thread.h> | |||
57 | #include <ddb/db_trap.h> | |||
58 | #include <ddb/db_watch.h> | |||
59 | #include <machine/db_interface.h> | |||
60 | #include <machine/machspl.h> | |||
61 | ||||
62 | #if MACH_KDB1 | |||
63 | /* Whether the kernel uses any debugging register. */ | |||
64 | static boolean_t kernel_dr; | |||
65 | #endif | |||
66 | /* Whether the current debug registers are zero. */ | |||
67 | static boolean_t zero_dr; | |||
68 | ||||
69 | void db_load_context(pcb_t pcb) | |||
70 | { | |||
71 | #if MACH_KDB1 | |||
72 | int s = splhigh(); | |||
73 | ||||
74 | if (kernel_dr) { | |||
75 | splx(s); | |||
76 | return; | |||
77 | } | |||
78 | #endif | |||
79 | /* Else set user debug registers, if any */ | |||
80 | unsigned int *dr = pcb->ims.ids.dr; | |||
81 | boolean_t will_zero_dr = !dr[0] && !dr[1] && !dr[2] && !dr[3] && !dr[7]; | |||
82 | ||||
83 | if (!(zero_dr && will_zero_dr)) | |||
84 | { | |||
85 | set_dr0(dr[0])({ register unsigned long _temp__ = (dr[0]); asm volatile("movl %0,%%dr0" : : "r" (_temp__)); }); | |||
86 | set_dr1(dr[1])({ register unsigned long _temp__ = (dr[1]); asm volatile("movl %0,%%dr1" : : "r" (_temp__)); }); | |||
87 | set_dr2(dr[2])({ register unsigned long _temp__ = (dr[2]); asm volatile("movl %0,%%dr2" : : "r" (_temp__)); }); | |||
88 | set_dr3(dr[3])({ register unsigned long _temp__ = (dr[3]); asm volatile("movl %0,%%dr3" : : "r" (_temp__)); }); | |||
89 | set_dr7(dr[7])({ register unsigned long _temp__ = (dr[7]); asm volatile("movl %0,%%dr7" : : "r" (_temp__)); }); | |||
90 | zero_dr = will_zero_dr; | |||
91 | } | |||
92 | ||||
93 | #if MACH_KDB1 | |||
94 | splx(s); | |||
95 | #endif | |||
96 | } | |||
97 | ||||
98 | void db_get_debug_state( | |||
99 | pcb_t pcb, | |||
100 | struct i386_debug_state *state) | |||
101 | { | |||
102 | *state = pcb->ims.ids; | |||
103 | } | |||
104 | ||||
105 | kern_return_t db_set_debug_state( | |||
106 | pcb_t pcb, | |||
107 | const struct i386_debug_state *state) | |||
108 | { | |||
109 | int i; | |||
110 | ||||
111 | for (i = 0; i <= 3; i++) | |||
112 | if (state->dr[i] < VM_MIN_ADDRESS(0) | |||
113 | || state->dr[i] >= VM_MAX_ADDRESS(0xc0000000UL)) | |||
114 | return KERN_INVALID_ARGUMENT4; | |||
115 | ||||
116 | pcb->ims.ids = *state; | |||
117 | ||||
118 | if (pcb == current_thread()(active_threads[(0)])->pcb) | |||
119 | db_load_context(pcb); | |||
120 | ||||
121 | return KERN_SUCCESS0; | |||
122 | } | |||
123 | ||||
124 | #if MACH_KDB1 | |||
125 | ||||
126 | struct i386_saved_state *i386_last_saved_statep; | |||
127 | struct i386_saved_state i386_nested_saved_state; | |||
128 | unsigned i386_last_kdb_sp; | |||
129 | ||||
130 | extern thread_t db_default_thread; | |||
131 | ||||
132 | static struct i386_debug_state ids; | |||
133 | ||||
134 | void db_dr ( | |||
135 | int num, | |||
136 | vm_offset_t linear_addr, | |||
137 | int type, | |||
138 | int len, | |||
139 | int persistence) | |||
140 | { | |||
141 | int s = splhigh(); | |||
142 | unsigned long dr7; | |||
143 | ||||
144 | if (!kernel_dr) { | |||
145 | if (!linear_addr) { | |||
146 | splx(s); | |||
147 | return; | |||
148 | } | |||
149 | kernel_dr = TRUE((boolean_t) 1); | |||
150 | /* Clear user debugging registers */ | |||
151 | set_dr7(0)({ register unsigned long _temp__ = (0); asm volatile("movl %0,%%dr7" : : "r" (_temp__)); }); | |||
152 | set_dr0(0)({ register unsigned long _temp__ = (0); asm volatile("movl %0,%%dr0" : : "r" (_temp__)); }); | |||
153 | set_dr1(0)({ register unsigned long _temp__ = (0); asm volatile("movl %0,%%dr1" : : "r" (_temp__)); }); | |||
154 | set_dr2(0)({ register unsigned long _temp__ = (0); asm volatile("movl %0,%%dr2" : : "r" (_temp__)); }); | |||
155 | set_dr3(0)({ register unsigned long _temp__ = (0); asm volatile("movl %0,%%dr3" : : "r" (_temp__)); }); | |||
156 | } | |||
157 | ||||
158 | ids.dr[num] = linear_addr; | |||
159 | switch (num) { | |||
160 | case 0: set_dr0(linear_addr)({ register unsigned long _temp__ = (linear_addr); asm volatile ("movl %0,%%dr0" : : "r" (_temp__)); }); break; | |||
161 | case 1: set_dr1(linear_addr)({ register unsigned long _temp__ = (linear_addr); asm volatile ("movl %0,%%dr1" : : "r" (_temp__)); }); break; | |||
162 | case 2: set_dr2(linear_addr)({ register unsigned long _temp__ = (linear_addr); asm volatile ("movl %0,%%dr2" : : "r" (_temp__)); }); break; | |||
163 | case 3: set_dr3(linear_addr)({ register unsigned long _temp__ = (linear_addr); asm volatile ("movl %0,%%dr3" : : "r" (_temp__)); }); break; | |||
164 | } | |||
165 | ||||
166 | /* Replace type/len/persistence for DRnum in dr7 */ | |||
167 | dr7 = get_dr7 ()({ register unsigned long _temp__; asm volatile("movl %%dr7, %0" : "=r" (_temp__)); _temp__; }); | |||
168 | dr7 &= ~(0xfUL << (4*num+16)) & ~(0x3UL << (2*num)); | |||
169 | dr7 |= (((len << 2) | type) << (4*num+16)) | (persistence << (2*num)); | |||
170 | set_dr7 (dr7)({ register unsigned long _temp__ = (dr7); asm volatile("movl %0,%%dr7" : : "r" (_temp__)); }); | |||
171 | ||||
172 | if (kernel_dr) { | |||
173 | if (!ids.dr[0] && !ids.dr[1] && !ids.dr[2] && !ids.dr[3]) { | |||
174 | /* Not used any more, switch back to user debugging registers */ | |||
175 | set_dr7 (0)({ register unsigned long _temp__ = (0); asm volatile("movl %0,%%dr7" : : "r" (_temp__)); }); | |||
176 | kernel_dr = FALSE((boolean_t) 0); | |||
177 | zero_dr = TRUE((boolean_t) 1); | |||
178 | db_load_context(current_thread()(active_threads[(0)])->pcb); | |||
179 | } | |||
180 | } | |||
181 | splx(s); | |||
182 | } | |||
183 | ||||
184 | boolean_t | |||
185 | db_set_hw_watchpoint( | |||
186 | const db_watchpoint_t watch, | |||
187 | unsigned num) | |||
188 | { | |||
189 | vm_size_t size = watch->hiaddr - watch->loaddr; | |||
190 | db_addr_t addr = watch->loaddr; | |||
191 | vm_offset_t kern_addr; | |||
192 | ||||
193 | if (num >= 4) | |||
194 | return FALSE((boolean_t) 0); | |||
195 | if (size != 1 && size != 2 && size != 4) | |||
196 | return FALSE((boolean_t) 0); | |||
197 | ||||
198 | if (addr & (size-1)) | |||
199 | /* Unaligned */ | |||
200 | return FALSE((boolean_t) 0); | |||
201 | ||||
202 | if (watch->task) { | |||
203 | if (db_user_to_kernel_address(watch->task, addr, &kern_addr, 1) < 0) | |||
204 | return FALSE((boolean_t) 0); | |||
205 | addr = kern_addr; | |||
206 | } | |||
207 | addr = kvtolin(addr)((vm_offset_t)(addr) - 0xC0000000UL + ((0xc0000000UL))); | |||
208 | ||||
209 | db_dr (num, addr, I386_DB_TYPE_W1, size-1, I386_DB_LOCAL1|I386_DB_GLOBAL2); | |||
210 | ||||
211 | db_printf("Hardware watchpoint %d set for %x\n", num, addr); | |||
212 | return TRUE((boolean_t) 1); | |||
213 | } | |||
214 | ||||
215 | boolean_t | |||
216 | db_clear_hw_watchpoint( | |||
217 | unsigned num) | |||
218 | { | |||
219 | if (num >= 4) | |||
220 | return FALSE((boolean_t) 0); | |||
221 | ||||
222 | db_dr (num, 0, 0, 0, 0); | |||
223 | return TRUE((boolean_t) 1); | |||
224 | } | |||
225 | ||||
226 | /* | |||
227 | * Print trap reason. | |||
228 | */ | |||
229 | void | |||
230 | kdbprinttrap( | |||
231 | int type, | |||
232 | int code) | |||
233 | { | |||
234 | printf("kernel: %s (%d), code=%x\n", | |||
235 | trap_name(type), type, code); | |||
236 | } | |||
237 | ||||
238 | /* | |||
239 | * kdb_trap - field a TRACE or BPT trap | |||
240 | */ | |||
241 | ||||
242 | extern jmp_buf_t *db_recover; | |||
243 | spl_t saved_ipl[NCPUS1]; /* just to know what was IPL before trap */ | |||
244 | ||||
245 | boolean_t | |||
246 | kdb_trap( | |||
247 | int type, | |||
248 | int code, | |||
249 | struct i386_saved_state *regs) | |||
250 | { | |||
251 | spl_t s; | |||
252 | ||||
253 | s = splhigh(); | |||
254 | saved_ipl[cpu_number()(0)] = s; | |||
255 | ||||
256 | switch (type) { | |||
| ||||
257 | case T_DEBUG1: /* single_step */ | |||
258 | { | |||
259 | int addr; | |||
260 | int status = get_dr6()({ register unsigned long _temp__; asm volatile("movl %%dr6, %0" : "=r" (_temp__)); _temp__; }); | |||
261 | ||||
262 | if (status & 0xf) { /* hmm hdw break */ | |||
263 | addr = status & 0x8 ? get_dr3()({ register unsigned long _temp__; asm volatile("movl %%dr3, %0" : "=r" (_temp__)); _temp__; }) : | |||
264 | status & 0x4 ? get_dr2()({ register unsigned long _temp__; asm volatile("movl %%dr2, %0" : "=r" (_temp__)); _temp__; }) : | |||
265 | status & 0x2 ? get_dr1()({ register unsigned long _temp__; asm volatile("movl %%dr1, %0" : "=r" (_temp__)); _temp__; }) : | |||
266 | get_dr0()({ register unsigned long _temp__; asm volatile("movl %%dr0, %0" : "=r" (_temp__)); _temp__; }); | |||
267 | regs->efl |= EFL_RF0x00010000; | |||
268 | db_single_step_cmd(addr, 0, 1, "p"); | |||
269 | } | |||
270 | } | |||
271 | case T_INT33: /* breakpoint */ | |||
272 | case T_WATCHPOINT17: /* watchpoint */ | |||
273 | case -1: /* keyboard interrupt */ | |||
274 | break; | |||
275 | ||||
276 | default: | |||
277 | if (db_recover) { | |||
278 | i386_nested_saved_state = *regs; | |||
279 | db_printf("Caught %s (%d), code = %x, pc = %x\n", | |||
280 | trap_name(type), type, code, regs->eip); | |||
281 | db_error(""); | |||
282 | /*NOTREACHED*/ | |||
283 | } | |||
284 | kdbprinttrap(type, code); | |||
285 | } | |||
286 | ||||
287 | #if NCPUS1 > 1 | |||
288 | if (db_enter()) | |||
289 | #endif /* NCPUS > 1 */ | |||
290 | { | |||
291 | i386_last_saved_statep = regs; | |||
292 | i386_last_kdb_sp = (unsigned) &type; | |||
293 | ||||
294 | /* XXX Should switch to ddb`s own stack here. */ | |||
295 | ||||
296 | ddb_regs = *regs; | |||
297 | if ((regs->cs & 0x3) == KERNEL_RING0) { | |||
298 | /* | |||
299 | * Kernel mode - esp and ss not saved | |||
300 | */ | |||
301 | ddb_regs.uesp = (int)®s->uesp; /* kernel stack pointer */ | |||
302 | ddb_regs.ss = KERNEL_DS(0x10 | 0); | |||
303 | } | |||
304 | ||||
305 | cnpollc(TRUE((boolean_t) 1)); | |||
306 | db_task_trap(type, code, (regs->cs & 0x3) != 0); | |||
307 | cnpollc(FALSE((boolean_t) 0)); | |||
308 | ||||
309 | regs->eip = ddb_regs.eip; | |||
310 | regs->efl = ddb_regs.efl; | |||
311 | regs->eax = ddb_regs.eax; | |||
312 | regs->ecx = ddb_regs.ecx; | |||
313 | regs->edx = ddb_regs.edx; | |||
314 | regs->ebx = ddb_regs.ebx; | |||
315 | if ((regs->cs & 0x3) != KERNEL_RING0) { | |||
316 | /* | |||
317 | * user mode - saved esp and ss valid | |||
318 | */ | |||
319 | regs->uesp = ddb_regs.uesp; /* user stack pointer */ | |||
320 | regs->ss = ddb_regs.ss & 0xffff; /* user stack segment */ | |||
321 | } | |||
322 | regs->ebp = ddb_regs.ebp; | |||
323 | regs->esi = ddb_regs.esi; | |||
324 | regs->edi = ddb_regs.edi; | |||
325 | regs->es = ddb_regs.es & 0xffff; | |||
326 | regs->cs = ddb_regs.cs & 0xffff; | |||
327 | regs->ds = ddb_regs.ds & 0xffff; | |||
328 | regs->fs = ddb_regs.fs & 0xffff; | |||
329 | regs->gs = ddb_regs.gs & 0xffff; | |||
330 | ||||
331 | if ((type == T_INT33) && | |||
332 | (db_get_task_value(regs->eip, BKPT_SIZE(1), FALSE((boolean_t) 0), TASK_NULL((task_t) 0)) | |||
333 | == BKPT_INST0xcc)) | |||
334 | regs->eip += BKPT_SIZE(1); | |||
335 | } | |||
336 | #if NCPUS1 > 1 | |||
337 | db_leave(); | |||
338 | #endif /* NCPUS > 1 */ | |||
339 | ||||
340 | splx(s); | |||
341 | return 1; | |||
342 | } | |||
| ||||
343 | ||||
344 | /* | |||
345 | * Enter KDB through a keyboard trap. | |||
346 | * We show the registers as of the keyboard interrupt | |||
347 | * instead of those at its call to KDB. | |||
348 | */ | |||
349 | struct int_regs { | |||
350 | long edi; | |||
351 | long esi; | |||
352 | long ebp; | |||
353 | long ebx; | |||
354 | struct i386_interrupt_state *is; | |||
355 | }; | |||
356 | ||||
357 | void | |||
358 | kdb_kentry( | |||
359 | struct int_regs *int_regs) | |||
360 | { | |||
361 | struct i386_interrupt_state *is = int_regs->is; | |||
362 | spl_t s = splhigh(); | |||
363 | ||||
364 | #if NCPUS1 > 1 | |||
365 | if (db_enter()) | |||
366 | #endif /* NCPUS > 1 */ | |||
367 | { | |||
368 | if ((is->cs & 0x3) != KERNEL_RING0) { | |||
369 | ddb_regs.uesp = ((int *)(is+1))[0]; | |||
370 | ddb_regs.ss = ((int *)(is+1))[1]; | |||
371 | } | |||
372 | else { | |||
373 | ddb_regs.ss = KERNEL_DS(0x10 | 0); | |||
374 | ddb_regs.uesp= (int)(is+1); | |||
375 | } | |||
376 | ddb_regs.efl = is->efl; | |||
377 | ddb_regs.cs = is->cs; | |||
378 | ddb_regs.eip = is->eip; | |||
379 | ddb_regs.eax = is->eax; | |||
380 | ddb_regs.ecx = is->ecx; | |||
381 | ddb_regs.edx = is->edx; | |||
382 | ddb_regs.ebx = int_regs->ebx; | |||
383 | ddb_regs.ebp = int_regs->ebp; | |||
384 | ddb_regs.esi = int_regs->esi; | |||
385 | ddb_regs.edi = int_regs->edi; | |||
386 | ddb_regs.ds = is->ds; | |||
387 | ddb_regs.es = is->es; | |||
388 | ddb_regs.fs = is->fs; | |||
389 | ddb_regs.gs = is->gs; | |||
390 | ||||
391 | cnpollc(TRUE((boolean_t) 1)); | |||
392 | db_task_trap(-1, 0, (ddb_regs.cs & 0x3) != 0); | |||
393 | cnpollc(FALSE((boolean_t) 0)); | |||
394 | ||||
395 | if ((ddb_regs.cs & 0x3) != KERNEL_RING0) { | |||
396 | ((int *)(is+1))[0] = ddb_regs.uesp; | |||
397 | ((int *)(is+1))[1] = ddb_regs.ss & 0xffff; | |||
398 | } | |||
399 | is->efl = ddb_regs.efl; | |||
400 | is->cs = ddb_regs.cs & 0xffff; | |||
401 | is->eip = ddb_regs.eip; | |||
402 | is->eax = ddb_regs.eax; | |||
403 | is->ecx = ddb_regs.ecx; | |||
404 | is->edx = ddb_regs.edx; | |||
405 | int_regs->ebx = ddb_regs.ebx; | |||
406 | int_regs->ebp = ddb_regs.ebp; | |||
407 | int_regs->esi = ddb_regs.esi; | |||
408 | int_regs->edi = ddb_regs.edi; | |||
409 | is->ds = ddb_regs.ds & 0xffff; | |||
410 | is->es = ddb_regs.es & 0xffff; | |||
411 | is->fs = ddb_regs.fs & 0xffff; | |||
412 | is->gs = ddb_regs.gs & 0xffff; | |||
413 | } | |||
414 | #if NCPUS1 > 1 | |||
415 | db_leave(); | |||
416 | #endif /* NCPUS > 1 */ | |||
417 | ||||
418 | (void) splx(s); | |||
419 | } | |||
420 | ||||
421 | boolean_t db_no_vm_fault = TRUE((boolean_t) 1); | |||
422 | ||||
423 | int | |||
424 | db_user_to_kernel_address( | |||
425 | const task_t task, | |||
426 | vm_offset_t addr, | |||
427 | vm_offset_t *kaddr, | |||
428 | int flag) | |||
429 | { | |||
430 | pt_entry_t *ptp; | |||
431 | boolean_t faulted = FALSE((boolean_t) 0); | |||
432 | ||||
433 | retry: | |||
434 | ptp = pmap_pte(task->map->pmap, addr); | |||
435 | if (ptp == PT_ENTRY_NULL((pt_entry_t *) 0) || (*ptp & INTEL_PTE_VALID0x00000001) == 0) { | |||
436 | if (!faulted && !db_no_vm_fault) { | |||
437 | kern_return_t err; | |||
438 | ||||
439 | faulted = TRUE((boolean_t) 1); | |||
440 | err = vm_fault( task->map, | |||
441 | trunc_page(addr)((vm_offset_t)(((vm_offset_t)(addr)) & ~((1 << 12)- 1))), | |||
442 | VM_PROT_READ((vm_prot_t) 0x01), | |||
443 | FALSE((boolean_t) 0), FALSE((boolean_t) 0), 0); | |||
444 | if (err == KERN_SUCCESS0) | |||
445 | goto retry; | |||
446 | } | |||
447 | if (flag) { | |||
448 | db_printf("\nno memory is assigned to address %08x\n", addr); | |||
449 | db_error(0); | |||
450 | /* NOTREACHED */ | |||
451 | } | |||
452 | return(-1); | |||
453 | } | |||
454 | *kaddr = ptetokv(*ptp)(((vm_offset_t)(((*ptp) & 0xfffff000)) + 0xC0000000UL)) + (addr & (INTEL_PGBYTES4096-1)); | |||
455 | return(0); | |||
456 | } | |||
457 | ||||
458 | /* | |||
459 | * Read bytes from kernel address space for debugger. | |||
460 | */ | |||
461 | ||||
462 | void | |||
463 | db_read_bytes( | |||
464 | vm_offset_t addr, | |||
465 | int size, | |||
466 | char *data, | |||
467 | task_t task) | |||
468 | { | |||
469 | char *src; | |||
470 | int n; | |||
471 | vm_offset_t kern_addr; | |||
472 | ||||
473 | src = (char *)addr; | |||
474 | if ((addr >= VM_MIN_KERNEL_ADDRESS0xC0000000UL && addr < VM_MAX_KERNEL_ADDRESS((0xffffffffUL) - ((0xc0000000UL)) + 0xC0000000UL)) || task == TASK_NULL((task_t) 0)) { | |||
475 | if (task == TASK_NULL((task_t) 0)) | |||
476 | task = db_current_task()(((active_threads[(0)]))? (active_threads[(0)])->task: ((task_t ) 0)); | |||
477 | while (--size >= 0) { | |||
478 | if (addr < VM_MIN_KERNEL_ADDRESS0xC0000000UL && task == TASK_NULL((task_t) 0)) { | |||
479 | db_printf("\nbad address %x\n", addr); | |||
480 | db_error(0); | |||
481 | /* NOTREACHED */ | |||
482 | } | |||
483 | addr++; | |||
484 | *data++ = *src++; | |||
485 | } | |||
486 | return; | |||
487 | } | |||
488 | while (size > 0) { | |||
489 | if (db_user_to_kernel_address(task, addr, &kern_addr, 1) < 0) | |||
490 | return; | |||
491 | src = (char *)kern_addr; | |||
492 | n = intel_trunc_page(addr+INTEL_PGBYTES)(((unsigned long)(addr+4096)) & ~(4096 -1)) - addr; | |||
493 | if (n > size) | |||
494 | n = size; | |||
495 | size -= n; | |||
496 | addr += n; | |||
497 | while (--n >= 0) | |||
498 | *data++ = *src++; | |||
499 | } | |||
500 | } | |||
501 | ||||
502 | /* | |||
503 | * Write bytes to kernel address space for debugger. | |||
504 | */ | |||
505 | void | |||
506 | db_write_bytes( | |||
507 | vm_offset_t addr, | |||
508 | int size, | |||
509 | char *data, | |||
510 | task_t task) | |||
511 | { | |||
512 | char *dst; | |||
513 | ||||
514 | pt_entry_t *ptep0 = 0; | |||
515 | pt_entry_t oldmap0 = 0; | |||
516 | vm_offset_t addr1; | |||
517 | pt_entry_t *ptep1 = 0; | |||
518 | pt_entry_t oldmap1 = 0; | |||
519 | extern char etext; | |||
520 | ||||
521 | if ((addr < VM_MIN_KERNEL_ADDRESS0xC0000000UL) ^ | |||
522 | ((addr + size) <= VM_MIN_KERNEL_ADDRESS0xC0000000UL)) { | |||
523 | db_error("\ncannot write data into mixed space\n"); | |||
524 | /* NOTREACHED */ | |||
525 | } | |||
526 | if (addr < VM_MIN_KERNEL_ADDRESS0xC0000000UL) { | |||
527 | if (task) { | |||
528 | db_write_bytes_user_space(addr, size, data, task); | |||
529 | return; | |||
530 | } else if (db_current_task()(((active_threads[(0)]))? (active_threads[(0)])->task: ((task_t ) 0)) == TASK_NULL((task_t) 0)) { | |||
531 | db_printf("\nbad address %x\n", addr); | |||
532 | db_error(0); | |||
533 | /* NOTREACHED */ | |||
534 | } | |||
535 | } | |||
536 | ||||
537 | if (addr >= VM_MIN_KERNEL_ADDRESS0xC0000000UL && | |||
538 | addr <= (vm_offset_t)&etext) | |||
539 | { | |||
540 | ptep0 = pmap_pte(kernel_pmap, addr); | |||
541 | oldmap0 = *ptep0; | |||
542 | *ptep0 |= INTEL_PTE_WRITE0x00000002; | |||
543 | ||||
544 | addr1 = i386_trunc_page(addr + size - 1)(((unsigned long)(addr + size - 1)) & ~(4096 -1)); | |||
545 | if (i386_trunc_page(addr)(((unsigned long)(addr)) & ~(4096 -1)) != addr1) { | |||
546 | /* data crosses a page boundary */ | |||
547 | ||||
548 | ptep1 = pmap_pte(kernel_pmap, addr1); | |||
549 | oldmap1 = *ptep1; | |||
550 | *ptep1 |= INTEL_PTE_WRITE0x00000002; | |||
551 | } | |||
552 | if (CPU_HAS_FEATURE(CPU_FEATURE_PGE)(cpu_features[(13) / 32] & (1 << ((13) % 32)))) | |||
553 | set_cr4(get_cr4() & ~CR4_PGE)({ register unsigned long _temp__ = (({ register unsigned long _temp__; asm volatile("mov %%cr4, %0" : "=r" (_temp__)); _temp__ ; }) & ~0x0080); asm volatile("mov %0, %%cr4" : : "r" (_temp__ )); }); | |||
554 | flush_tlb()({ register unsigned long _temp__ = (({ register unsigned long _temp__; asm volatile("mov %%cr3, %0" : "=r" (_temp__)); _temp__ ; })); asm volatile("mov %0, %%cr3" : : "r" (_temp__) : "memory" ); }); | |||
555 | } | |||
556 | ||||
557 | dst = (char *)addr; | |||
558 | ||||
559 | while (--size >= 0) | |||
560 | *dst++ = *data++; | |||
561 | ||||
562 | if (ptep0) { | |||
563 | *ptep0 = oldmap0; | |||
564 | if (ptep1) { | |||
565 | *ptep1 = oldmap1; | |||
566 | } | |||
567 | flush_tlb()({ register unsigned long _temp__ = (({ register unsigned long _temp__; asm volatile("mov %%cr3, %0" : "=r" (_temp__)); _temp__ ; })); asm volatile("mov %0, %%cr3" : : "r" (_temp__) : "memory" ); }); | |||
568 | if (CPU_HAS_FEATURE(CPU_FEATURE_PGE)(cpu_features[(13) / 32] & (1 << ((13) % 32)))) | |||
569 | set_cr4(get_cr4() | CR4_PGE)({ register unsigned long _temp__ = (({ register unsigned long _temp__; asm volatile("mov %%cr4, %0" : "=r" (_temp__)); _temp__ ; }) | 0x0080); asm volatile("mov %0, %%cr4" : : "r" (_temp__ )); }); | |||
570 | } | |||
571 | } | |||
572 | ||||
573 | void | |||
574 | db_write_bytes_user_space( | |||
575 | vm_offset_t addr, | |||
576 | int size, | |||
577 | char *data, | |||
578 | task_t task) | |||
579 | { | |||
580 | char *dst; | |||
581 | int n; | |||
582 | vm_offset_t kern_addr; | |||
583 | ||||
584 | while (size > 0) { | |||
585 | if (db_user_to_kernel_address(task, addr, &kern_addr, 1) < 0) | |||
586 | return; | |||
587 | dst = (char *)kern_addr; | |||
588 | n = intel_trunc_page(addr+INTEL_PGBYTES)(((unsigned long)(addr+4096)) & ~(4096 -1)) - addr; | |||
589 | if (n > size) | |||
590 | n = size; | |||
591 | size -= n; | |||
592 | addr += n; | |||
593 | while (--n >= 0) | |||
594 | *dst++ = *data++; | |||
595 | } | |||
596 | } | |||
597 | ||||
598 | boolean_t | |||
599 | db_check_access( | |||
600 | vm_offset_t addr, | |||
601 | int size, | |||
602 | task_t task) | |||
603 | { | |||
604 | int n; | |||
605 | vm_offset_t kern_addr; | |||
606 | ||||
607 | if (addr >= VM_MIN_KERNEL_ADDRESS0xC0000000UL) { | |||
608 | if (kernel_task == TASK_NULL((task_t) 0)) | |||
609 | return TRUE((boolean_t) 1); | |||
610 | task = kernel_task; | |||
611 | } else if (task == TASK_NULL((task_t) 0)) { | |||
612 | if (current_thread()(active_threads[(0)]) == THREAD_NULL((thread_t) 0)) | |||
613 | return FALSE((boolean_t) 0); | |||
614 | task = current_thread()(active_threads[(0)])->task; | |||
615 | } | |||
616 | while (size > 0) { | |||
617 | if (db_user_to_kernel_address(task, addr, &kern_addr, 0) < 0) | |||
618 | return FALSE((boolean_t) 0); | |||
619 | n = intel_trunc_page(addr+INTEL_PGBYTES)(((unsigned long)(addr+4096)) & ~(4096 -1)) - addr; | |||
620 | if (n > size) | |||
621 | n = size; | |||
622 | size -= n; | |||
623 | addr += n; | |||
624 | } | |||
625 | return TRUE((boolean_t) 1); | |||
626 | } | |||
627 | ||||
628 | boolean_t | |||
629 | db_phys_eq( | |||
630 | task_t task1, | |||
631 | vm_offset_t addr1, | |||
632 | const task_t task2, | |||
633 | vm_offset_t addr2) | |||
634 | { | |||
635 | vm_offset_t kern_addr1, kern_addr2; | |||
636 | ||||
637 | if (addr1 >= VM_MIN_KERNEL_ADDRESS0xC0000000UL || addr2 >= VM_MIN_KERNEL_ADDRESS0xC0000000UL) | |||
638 | return FALSE((boolean_t) 0); | |||
639 | if ((addr1 & (INTEL_PGBYTES4096-1)) != (addr2 & (INTEL_PGBYTES4096-1))) | |||
640 | return FALSE((boolean_t) 0); | |||
641 | if (task1 == TASK_NULL((task_t) 0)) { | |||
642 | if (current_thread()(active_threads[(0)]) == THREAD_NULL((thread_t) 0)) | |||
643 | return FALSE((boolean_t) 0); | |||
644 | task1 = current_thread()(active_threads[(0)])->task; | |||
645 | } | |||
646 | if (db_user_to_kernel_address(task1, addr1, &kern_addr1, 0) < 0 | |||
647 | || db_user_to_kernel_address(task2, addr2, &kern_addr2, 0) < 0) | |||
648 | return FALSE((boolean_t) 0); | |||
649 | return(kern_addr1 == kern_addr2); | |||
650 | } | |||
651 | ||||
652 | #define DB_USER_STACK_ADDR(0xC0000000UL) (VM_MIN_KERNEL_ADDRESS0xC0000000UL) | |||
653 | #define DB_NAME_SEARCH_LIMIT((0xC0000000UL)-(4096*3)) (DB_USER_STACK_ADDR(0xC0000000UL)-(INTEL_PGBYTES4096*3)) | |||
654 | ||||
655 | #define GNU | |||
656 | ||||
657 | #ifndef GNU | |||
658 | static boolean_t | |||
659 | db_search_null( | |||
660 | const task_t task, | |||
661 | vm_offset_t *svaddr, | |||
662 | vm_offset_t evaddr, | |||
663 | vm_offset_t *skaddr, | |||
664 | int flag) | |||
665 | { | |||
666 | unsigned vaddr; | |||
667 | unsigned *kaddr; | |||
668 | ||||
669 | kaddr = (unsigned *)*skaddr; | |||
670 | for (vaddr = *svaddr; vaddr > evaddr; ) { | |||
671 | if (vaddr % INTEL_PGBYTES4096 == 0) { | |||
672 | vaddr -= sizeof(unsigned); | |||
673 | if (db_user_to_kernel_address(task, vaddr, skaddr, 0) < 0) | |||
674 | return FALSE((boolean_t) 0); | |||
675 | kaddr = (vm_offset_t *)*skaddr; | |||
676 | } else { | |||
677 | vaddr -= sizeof(unsigned); | |||
678 | kaddr--; | |||
679 | } | |||
680 | if ((*kaddr == 0) ^ (flag == 0)) { | |||
681 | *svaddr = vaddr; | |||
682 | *skaddr = (unsigned)kaddr; | |||
683 | return TRUE((boolean_t) 1); | |||
684 | } | |||
685 | } | |||
686 | return FALSE((boolean_t) 0); | |||
687 | } | |||
688 | #endif /* GNU */ | |||
689 | ||||
690 | #ifdef GNU | |||
691 | static boolean_t | |||
692 | looks_like_command( | |||
693 | const task_t task, | |||
694 | char* kaddr) | |||
695 | { | |||
696 | char *c; | |||
697 | ||||
698 | assert(!((vm_offset_t) kaddr & (INTEL_PGBYTES-1)))((!((vm_offset_t) kaddr & (4096 -1))) ? (void) (0) : Assert ("!((vm_offset_t) kaddr & (INTEL_PGBYTES-1))", "../i386/i386/db_interface.c" , 698)); | |||
699 | ||||
700 | /* | |||
701 | * Must be the environment. | |||
702 | */ | |||
703 | if (!memcmp(kaddr, "PATH=", 5) || !memcmp(kaddr, "TERM=", 5) || !memcmp(kaddr, "SHELL=", 6) || !memcmp(kaddr, "LOCAL_PART=", 11) || !memcmp(kaddr, "LC_ALL=", 7)) | |||
704 | return FALSE((boolean_t) 0); | |||
705 | ||||
706 | /* | |||
707 | * This is purely heuristical but works quite nicely. | |||
708 | * We know that it should look like words separated by \0, and | |||
709 | * eventually only \0s. | |||
710 | */ | |||
711 | c = kaddr; | |||
712 | while (c < kaddr + INTEL_PGBYTES4096) { | |||
713 | if (!*c) { | |||
714 | if (c == kaddr) | |||
715 | /* Starts by \0. */ | |||
716 | return FALSE((boolean_t) 0); | |||
717 | break; | |||
718 | } | |||
719 | while (c < kaddr + INTEL_PGBYTES4096 && *c) | |||
720 | c++; | |||
721 | if (c < kaddr + INTEL_PGBYTES4096) | |||
722 | c++; /* Skip \0 */ | |||
723 | } | |||
724 | /* | |||
725 | * Check that the remainder is just \0s. | |||
726 | */ | |||
727 | while (c < kaddr + INTEL_PGBYTES4096) | |||
728 | if (*c++) | |||
729 | return FALSE((boolean_t) 0); | |||
730 | ||||
731 | return TRUE((boolean_t) 1); | |||
732 | } | |||
733 | #endif /* GNU */ | |||
734 | ||||
735 | void | |||
736 | db_task_name( | |||
737 | const task_t task) | |||
738 | { | |||
739 | char *p; | |||
740 | int n; | |||
741 | vm_offset_t vaddr, kaddr; | |||
742 | unsigned sp; | |||
743 | ||||
744 | if (task->name[0]) { | |||
745 | db_printf("%s", task->name); | |||
746 | return; | |||
747 | } | |||
748 | ||||
749 | #ifdef GNU | |||
750 | /* | |||
751 | * GNU Hurd-specific heuristics. | |||
752 | */ | |||
753 | ||||
754 | /* Heuristical address first. */ | |||
755 | vaddr = 0x1026000; | |||
756 | if (db_user_to_kernel_address(task, vaddr, &kaddr, 0) >= 0 && | |||
757 | looks_like_command(task, (char*) kaddr)) | |||
758 | goto ok; | |||
759 | ||||
760 | /* Try to catch SP of the main thread. */ | |||
761 | thread_t thread; | |||
762 | ||||
763 | task_lock(task); | |||
764 | thread = (thread_t) queue_first(&task->thread_list)((&task->thread_list)->next); | |||
765 | if (!thread) { | |||
766 | task_unlock(task)((void)(&(task)->lock)); | |||
767 | db_printf(DB_NULL_TASK_NAME"? "); | |||
768 | return; | |||
769 | } | |||
770 | sp = thread->pcb->iss.uesp; | |||
771 | task_unlock(task)((void)(&(task)->lock)); | |||
772 | ||||
773 | vaddr = (sp & ~(INTEL_PGBYTES4096 - 1)) + INTEL_PGBYTES4096; | |||
774 | while (1) { | |||
775 | if (db_user_to_kernel_address(task, vaddr, &kaddr, 0) < 0) | |||
776 | return; | |||
777 | if (looks_like_command(task, (char*) kaddr)) | |||
778 | break; | |||
779 | vaddr += INTEL_PGBYTES4096; | |||
780 | } | |||
781 | #else /* GNU */ | |||
782 | vaddr = DB_USER_STACK_ADDR(0xC0000000UL); | |||
783 | kaddr = 0; | |||
784 | ||||
785 | /* | |||
786 | * skip nulls at the end | |||
787 | */ | |||
788 | if (!db_search_null(task, &vaddr, DB_NAME_SEARCH_LIMIT((0xC0000000UL)-(4096*3)), &kaddr, 0)) { | |||
789 | db_printf(DB_NULL_TASK_NAME"? "); | |||
790 | return; | |||
791 | } | |||
792 | /* | |||
793 | * search start of args | |||
794 | */ | |||
795 | if (!db_search_null(task, &vaddr, DB_NAME_SEARCH_LIMIT((0xC0000000UL)-(4096*3)), &kaddr, 1)) { | |||
796 | db_printf(DB_NULL_TASK_NAME"? "); | |||
797 | return; | |||
798 | } | |||
799 | #endif /* GNU */ | |||
800 | ||||
801 | ok: | |||
802 | n = DB_TASK_NAME_LEN23-1; | |||
803 | #ifdef GNU | |||
804 | p = (char *)kaddr; | |||
805 | for (; n > 0; vaddr++, p++, n--) { | |||
806 | #else /* GNU */ | |||
807 | p = (char *)kaddr + sizeof(unsigned); | |||
808 | for (vaddr += sizeof(int); vaddr < DB_USER_STACK_ADDR(0xC0000000UL) && n > 0; | |||
809 | vaddr++, p++, n--) { | |||
810 | #endif /* GNU */ | |||
811 | if (vaddr % INTEL_PGBYTES4096 == 0) { | |||
812 | (void)db_user_to_kernel_address(task, vaddr, &kaddr, 0); | |||
813 | p = (char*)kaddr; | |||
814 | } | |||
815 | db_printf("%c", (*p < ' ' || *p > '~')? ' ': *p); | |||
816 | } | |||
817 | while (n-- >= 0) /* compare with >= 0 for one more space */ | |||
818 | db_printf(" "); | |||
819 | } | |||
820 | ||||
821 | #endif /* MACH_KDB */ |