| 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 */ |