1/* 2 * Copyright (c) 2003-2007 Apple Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28 29#include <mach/mach_types.h> 30#include <mach/task.h> 31#include <mach/thread_act.h> 32 33#include <kern/kern_types.h> 34#include <kern/processor.h> 35#include <kern/thread.h> 36 37#include <vm/vm_map.h> 38#include <vm/pmap.h> 39 40#include <chud/chud_xnu.h> 41#include <chud/chud_xnu_private.h> 42 43#include <i386/misc_protos.h> 44#include <i386/proc_reg.h> 45#include <i386/mp_desc.h> 46 47#pragma mark **** thread state **** 48 49__private_extern__ kern_return_t 50chudxnu_thread_user_state_available(thread_t thread) 51{ 52#pragma unused (thread) 53 return KERN_SUCCESS; 54} 55 56__private_extern__ kern_return_t 57chudxnu_thread_get_state( 58 thread_t thread, 59 thread_flavor_t flavor, 60 thread_state_t tstate, 61 mach_msg_type_number_t *count, 62 boolean_t user_only) 63{ 64 if (user_only) { 65 /* We can't get user state for kernel threads */ 66 if (thread->task == kernel_task) 67 return KERN_FAILURE; 68 /* this properly handles deciding whether or not the thread is 64 bit or not */ 69 return machine_thread_get_state(thread, flavor, tstate, count); 70 } else { 71 // i386 machine_thread_get_kern_state() is different from the PPC version which returns 72 // the previous save area - user or kernel - rather than kernel or NULL if no kernel 73 // interrupt state available 74 75 // the real purpose of this branch is the following: 76 // the user doesn't care if the thread states are user or kernel, he 77 // just wants the thread state, so we need to determine the proper one 78 // to return, kernel or user, for the given thread. 79 if(thread == current_thread() && current_cpu_datap()->cpu_int_state) { 80 // the above are conditions where we possibly can read the kernel 81 // state. we still need to determine if this interrupt happened in 82 // kernel or user context 83 if(USER_STATE(thread) == current_cpu_datap()->cpu_int_state && 84 current_cpu_datap()->cpu_interrupt_level == 1) { 85 // interrupt happened in user land 86 return machine_thread_get_state(thread, flavor, tstate, count); 87 } else { 88 // kernel interrupt. 89 return machine_thread_get_kern_state(thread, flavor, tstate, count); 90 } 91 } else { 92 // get the user-mode thread state 93 return machine_thread_get_state(thread, flavor, tstate, count); 94 } 95 } 96} 97 98__private_extern__ kern_return_t 99chudxnu_thread_set_state( 100 thread_t thread, 101 thread_flavor_t flavor, 102 thread_state_t tstate, 103 mach_msg_type_number_t count, 104 boolean_t user_only) 105{ 106#pragma unused (user_only) 107 return machine_thread_set_state(thread, flavor, tstate, count); 108} 109 110#pragma mark **** task memory read/write **** 111 112__private_extern__ kern_return_t 113chudxnu_task_read( 114 task_t task, 115 void *kernaddr, 116 uint64_t usraddr, 117 vm_size_t size) 118{ 119 kern_return_t ret = KERN_SUCCESS; 120 boolean_t old_level; 121 122 if(ml_at_interrupt_context()) { 123 return KERN_FAILURE; // Can't look at tasks on interrupt stack 124 } 125 126 /* 127 * pmap layer requires interrupts to be on 128 */ 129 old_level = ml_set_interrupts_enabled(TRUE); 130 131 if(current_task()==task) { 132 133 if(copyin(usraddr, kernaddr, size)) { 134 ret = KERN_FAILURE; 135 } 136 } else { 137 vm_map_t map = get_task_map(task); 138 ret = vm_map_read_user(map, usraddr, kernaddr, size); 139 } 140 141 ml_set_interrupts_enabled(old_level); 142 143 return ret; 144} 145 146__private_extern__ kern_return_t 147chudxnu_task_write( 148 task_t task, 149 uint64_t useraddr, 150 void *kernaddr, 151 vm_size_t size) 152{ 153 kern_return_t ret = KERN_SUCCESS; 154 boolean_t old_level; 155 156 if(ml_at_interrupt_context()) { 157 return KERN_FAILURE; // can't poke into tasks on interrupt stack 158 } 159 160 /* 161 * pmap layer requires interrupts to be on 162 */ 163 old_level = ml_set_interrupts_enabled(TRUE); 164 165 if(current_task()==task) { 166 167 if(copyout(kernaddr, useraddr, size)) { 168 ret = KERN_FAILURE; 169 } 170 } else { 171 vm_map_t map = get_task_map(task); 172 ret = vm_map_write_user(map, kernaddr, useraddr, size); 173 } 174 175 ml_set_interrupts_enabled(old_level); 176 177 return ret; 178} 179 180__private_extern__ kern_return_t 181chudxnu_kern_read(void *dstaddr, vm_offset_t srcaddr, vm_size_t size) 182{ 183 return (ml_nofault_copy(srcaddr, (vm_offset_t) dstaddr, size) == size ? 184 KERN_SUCCESS: KERN_FAILURE); 185} 186 187__private_extern__ kern_return_t 188chudxnu_kern_write( 189 vm_offset_t dstaddr, 190 void *srcaddr, 191 vm_size_t size) 192{ 193 return (ml_nofault_copy((vm_offset_t) srcaddr, dstaddr, size) == size ? 194 KERN_SUCCESS: KERN_FAILURE); 195} 196 197#define VALID_STACK_ADDRESS(supervisor, addr, minKernAddr, maxKernAddr) (supervisor ? (addr>=minKernAddr && addr<=maxKernAddr) : TRUE) 198// don't try to read in the hole 199#define VALID_STACK_ADDRESS64(supervisor, addr, minKernAddr, maxKernAddr) \ 200(supervisor ? (addr >= minKernAddr && addr <= maxKernAddr) : \ 201(addr != 0 && (addr <= 0x00007FFFFFFFFFFFULL || addr >= 0xFFFF800000000000ULL))) 202 203typedef struct _cframe64_t { 204 uint64_t prevFP; // can't use a real pointer here until we're a 64 bit kernel 205 uint64_t caller; 206 uint64_t args[0]; 207}cframe64_t; 208 209 210typedef struct _cframe_t { 211 struct _cframe_t *prev; // when we go 64 bits, this needs to be capped at 32 bits 212 uint32_t caller; 213 uint32_t args[0]; 214} cframe_t; 215 216extern void * find_user_regs(thread_t); 217extern x86_saved_state32_t *find_kern_regs(thread_t); 218 219static kern_return_t do_backtrace32( 220 task_t task, 221 thread_t thread, 222 x86_saved_state32_t *regs, 223 uint64_t *frames, 224 mach_msg_type_number_t *start_idx, 225 mach_msg_type_number_t max_idx, 226 boolean_t supervisor) 227{ 228 uint32_t tmpWord = 0UL; 229 uint64_t currPC = (uint64_t) regs->eip; 230 uint64_t currFP = (uint64_t) regs->ebp; 231 uint64_t prevPC = 0ULL; 232 uint64_t prevFP = 0ULL; 233 uint64_t kernStackMin = thread->kernel_stack; 234 uint64_t kernStackMax = kernStackMin + KERNEL_STACK_SIZE; 235 mach_msg_type_number_t ct = *start_idx; 236 kern_return_t kr = KERN_FAILURE; 237 238 if(ct >= max_idx) 239 return KERN_RESOURCE_SHORTAGE; // no frames traced 240 241 frames[ct++] = currPC; 242 243 // build a backtrace of this 32 bit state. 244 while(VALID_STACK_ADDRESS(supervisor, currFP, kernStackMin, kernStackMax)) { 245 cframe_t *fp = (cframe_t *) (uint32_t) currFP; 246 247 if(!currFP) { 248 currPC = 0; 249 break; 250 } 251 252 if(ct >= max_idx) { 253 *start_idx = ct; 254 return KERN_RESOURCE_SHORTAGE; 255 } 256 257 /* read our caller */ 258 if(supervisor) { 259 kr = chudxnu_kern_read(&tmpWord, (vm_offset_t) &fp->caller, sizeof(uint32_t)); 260 } else { 261 kr = chudxnu_task_read(task, &tmpWord, (vm_offset_t) &fp->caller, sizeof(uint32_t)); 262 } 263 264 if(kr != KERN_SUCCESS) { 265 currPC = 0ULL; 266 break; 267 } 268 269 currPC = (uint64_t) tmpWord; // promote 32 bit address 270 271 /* 272 * retrive contents of the frame pointer and advance to the next stack 273 * frame if it's valid 274 */ 275 prevFP = 0; 276 if(supervisor) { 277 kr = chudxnu_kern_read(&tmpWord, (vm_offset_t)&fp->prev, sizeof(uint32_t)); 278 } else { 279 kr = chudxnu_task_read(task, &tmpWord, (vm_offset_t)&fp->prev, sizeof(uint32_t)); 280 } 281 prevFP = (uint64_t) tmpWord; // promote 32 bit address 282 283 if(prevFP) { 284 frames[ct++] = currPC; 285 prevPC = currPC; 286 } 287 if(prevFP < currFP) { 288 break; 289 } else { 290 currFP = prevFP; 291 } 292 } 293 294 *start_idx = ct; 295 return KERN_SUCCESS; 296} 297 298static kern_return_t do_backtrace64( 299 task_t task, 300 thread_t thread, 301 x86_saved_state64_t *regs, 302 uint64_t *frames, 303 mach_msg_type_number_t *start_idx, 304 mach_msg_type_number_t max_idx, 305 boolean_t supervisor) 306{ 307 uint64_t currPC = regs->isf.rip; 308 uint64_t currFP = regs->rbp; 309 uint64_t prevPC = 0ULL; 310 uint64_t prevFP = 0ULL; 311 uint64_t kernStackMin = (uint64_t)thread->kernel_stack; 312 uint64_t kernStackMax = (uint64_t)kernStackMin + KERNEL_STACK_SIZE; 313 mach_msg_type_number_t ct = *start_idx; 314 kern_return_t kr = KERN_FAILURE; 315 316 if(*start_idx >= max_idx) 317 return KERN_RESOURCE_SHORTAGE; // no frames traced 318 319 frames[ct++] = currPC; 320 321 // build a backtrace of this 32 bit state. 322 while(VALID_STACK_ADDRESS64(supervisor, currFP, kernStackMin, kernStackMax)) { 323 // this is the address where caller lives in the user thread 324 uint64_t caller = currFP + sizeof(uint64_t); 325 326 if(!currFP) { 327 currPC = 0; 328 break; 329 } 330 331 if(ct >= max_idx) { 332 *start_idx = ct; 333 return KERN_RESOURCE_SHORTAGE; 334 } 335 336 /* read our caller */ 337 if(supervisor) { 338 kr = KERN_FAILURE; 339 } else { 340 kr = chudxnu_task_read(task, &currPC, caller, sizeof(uint64_t)); 341 } 342 343 if(kr != KERN_SUCCESS) { 344 currPC = 0ULL; 345 break; 346 } 347 348 /* 349 * retrive contents of the frame pointer and advance to the next stack 350 * frame if it's valid 351 */ 352 prevFP = 0; 353 if(supervisor) { 354 kr = KERN_FAILURE; 355 } else { 356 kr = chudxnu_task_read(task, &prevFP, currFP, sizeof(uint64_t)); 357 } 358 359 if(VALID_STACK_ADDRESS64(supervisor, prevFP, kernStackMin, kernStackMax)) { 360 frames[ct++] = currPC; 361 prevPC = currPC; 362 } 363 if(prevFP < currFP) { 364 break; 365 } else { 366 currFP = prevFP; 367 } 368 } 369 370 *start_idx = ct; 371 return KERN_SUCCESS; 372} 373 374__private_extern__ 375kern_return_t chudxnu_thread_get_callstack64( 376 thread_t thread, 377 uint64_t *callstack, 378 mach_msg_type_number_t *count, 379 boolean_t user_only) 380{ 381 kern_return_t kr = KERN_FAILURE; 382 task_t task = thread->task; 383 uint64_t currPC = 0; 384 boolean_t supervisor = FALSE; 385 mach_msg_type_number_t bufferIndex = 0; 386 mach_msg_type_number_t bufferMaxIndex = *count; 387 x86_saved_state_t *tagged_regs = NULL; // kernel register state 388 x86_saved_state64_t *regs64 = NULL; 389 x86_saved_state32_t *regs32 = NULL; 390 x86_saved_state32_t *u_regs32 = NULL; 391 x86_saved_state64_t *u_regs64 = NULL; 392 393 if(ml_at_interrupt_context()) { 394 395 if(user_only) { 396 /* can't backtrace user state on interrupt stack. */ 397 return KERN_FAILURE; 398 } 399 400 /* backtracing at interrupt context? */ 401 if(thread == current_thread() && current_cpu_datap()->cpu_int_state) { 402 /* 403 * Locate the registers for the interrupted thread, assuming it is 404 * current_thread(). 405 */ 406 tagged_regs = current_cpu_datap()->cpu_int_state; 407 408 if(is_saved_state64(tagged_regs)) { 409 /* 64 bit registers */ 410 regs64 = saved_state64(tagged_regs); 411 supervisor = ((regs64->isf.cs & SEL_PL) != SEL_PL_U); 412 } else { 413 /* 32 bit registers */ 414 regs32 = saved_state32(tagged_regs); 415 supervisor = ((regs32->cs & SEL_PL) != SEL_PL_U); 416 } 417 } 418 } 419 420 if(!tagged_regs) { 421 /* 422 * not at interrupt context, or tracing a different thread than 423 * current_thread() at interrupt context 424 */ 425 tagged_regs = USER_STATE(thread); 426 if(is_saved_state64(tagged_regs)) { 427 /* 64 bit registers */ 428 regs64 = saved_state64(tagged_regs); 429 supervisor = ((regs64->isf.cs & SEL_PL) != SEL_PL_U); 430 } else { 431 /* 32 bit registers */ 432 regs32 = saved_state32(tagged_regs); 433 supervisor = ((regs32->cs & SEL_PL) != SEL_PL_U); 434 } 435 } 436 437 *count = 0; 438 439 if(supervisor) { 440 // the caller only wants a user callstack. 441 if(user_only) { 442 // bail - we've only got kernel state 443 return KERN_FAILURE; 444 } 445 } else { 446 // regs32(64) is not in supervisor mode. 447 u_regs32 = regs32; 448 u_regs64 = regs64; 449 regs32 = NULL; 450 regs64 = NULL; 451 } 452 453 if (user_only) { 454 /* we only want to backtrace the user mode */ 455 if(!(u_regs32 || u_regs64)) { 456 /* no user state to look at */ 457 return KERN_FAILURE; 458 } 459 } 460 461 /* 462 * Order of preference for top of stack: 463 * 64 bit kernel state (not likely) 464 * 32 bit kernel state 465 * 64 bit user land state 466 * 32 bit user land state 467 */ 468 469 if(regs64) { 470 currPC = regs64->isf.rip; 471 } else if(regs32) { 472 currPC = (uint64_t) regs32->eip; 473 } else if(u_regs64) { 474 currPC = u_regs64->isf.rip; 475 } else if(u_regs32) { 476 currPC = (uint64_t) u_regs32->eip; 477 } 478 479 if(!currPC) { 480 /* no top of the stack, bail out */ 481 return KERN_FAILURE; 482 } 483 484 bufferIndex = 0; 485 486 if(bufferMaxIndex < 1) { 487 *count = 0; 488 return KERN_RESOURCE_SHORTAGE; 489 } 490 491 /* backtrace kernel */ 492 if(regs64) { 493 uint64_t rsp = 0ULL; 494 495 // backtrace the 64bit side. 496 kr = do_backtrace64(task, thread, regs64, callstack, &bufferIndex, 497 bufferMaxIndex, TRUE); 498 499 if(KERN_SUCCESS == chudxnu_kern_read(&rsp, (addr64_t) regs64->isf.rsp, sizeof(uint64_t)) && 500 bufferIndex < bufferMaxIndex) { 501 callstack[bufferIndex++] = rsp; 502 } 503 504 } else if(regs32) { 505 uint32_t esp = 0UL; 506 507 // backtrace the 32bit side. 508 kr = do_backtrace32(task, thread, regs32, callstack, &bufferIndex, 509 bufferMaxIndex, TRUE); 510 511 if(KERN_SUCCESS == chudxnu_kern_read(&esp, (addr64_t) regs32->uesp, sizeof(uint32_t)) && 512 bufferIndex < bufferMaxIndex) { 513 callstack[bufferIndex++] = (uint64_t) esp; 514 } 515 } else if(u_regs64) { 516 /* backtrace user land */ 517 uint64_t rsp = 0ULL; 518 519 kr = do_backtrace64(task, thread, u_regs64, callstack, &bufferIndex, 520 bufferMaxIndex, FALSE); 521 522 if(KERN_SUCCESS == chudxnu_task_read(task, &rsp, (addr64_t) u_regs64->isf.rsp, sizeof(uint64_t)) && 523 bufferIndex < bufferMaxIndex) { 524 callstack[bufferIndex++] = rsp; 525 } 526 527 } else if(u_regs32) { 528 uint32_t esp = 0UL; 529 530 kr = do_backtrace32(task, thread, u_regs32, callstack, &bufferIndex, 531 bufferMaxIndex, FALSE); 532 533 if(KERN_SUCCESS == chudxnu_task_read(task, &esp, (addr64_t) u_regs32->uesp, sizeof(uint32_t)) && 534 bufferIndex < bufferMaxIndex) { 535 callstack[bufferIndex++] = (uint64_t) esp; 536 } 537 } 538 539 *count = bufferIndex; 540 return kr; 541} 542 543#pragma mark **** DEPRECATED **** 544 545// DEPRECATED 546__private_extern__ kern_return_t 547chudxnu_thread_get_callstack( 548 thread_t thread, 549 uint32_t *callStack, 550 mach_msg_type_number_t *count, 551 boolean_t user_only) 552{ 553 kern_return_t kr; 554 task_t task = thread->task; 555 uint32_t currPC; 556 uint32_t currFP; 557 uint32_t prevFP = 0; 558 uint32_t prevPC = 0; 559 uint32_t esp = 0; 560 uint32_t kernStackMin = thread->kernel_stack; 561 uint32_t kernStackMax = kernStackMin + KERNEL_STACK_SIZE; 562 uint32_t *buffer = callStack; 563 int bufferIndex = 0; 564 int bufferMaxIndex = *count; 565 boolean_t supervisor; 566 x86_saved_state32_t *regs = NULL; 567 568 if (user_only) { 569 /* We can't get user state for kernel threads */ 570 if (task == kernel_task) { 571 return KERN_FAILURE; 572 } 573 regs = USER_REGS32(thread); 574 } else { 575 regs = saved_state32(current_cpu_datap()->cpu_int_state); 576 } 577 578 if (regs == NULL) { 579 *count = 0; 580 return KERN_FAILURE; 581 } 582 583 supervisor = ((regs->cs & SEL_PL) != SEL_PL_U); 584 585 currPC = regs->eip; 586 currFP = regs->ebp; 587 588 bufferIndex = 0; 589 if(!supervisor) 590 bufferMaxIndex -= 1; // allot space for saving userland %esp on stack 591 if (bufferMaxIndex < 1) { 592 *count = 0; 593 return KERN_RESOURCE_SHORTAGE; 594 } 595 buffer[bufferIndex++] = currPC; //save PC in position 0. 596 597 // Now, fill buffer with stack backtraces. 598 while (VALID_STACK_ADDRESS(supervisor, currFP, kernStackMin, kernStackMax)) { 599 cframe_t *fp = (cframe_t *) currFP; 600 601 if (bufferIndex >= bufferMaxIndex) { 602 *count = bufferMaxIndex; 603 return KERN_RESOURCE_SHORTAGE; 604 } 605 606 if (supervisor) { 607 kr = chudxnu_kern_read( 608 &currPC, 609 (vm_offset_t) &fp->caller, 610 sizeof(currPC)); 611 } else { 612 kr = chudxnu_task_read( 613 task, 614 &currPC, 615 (vm_offset_t) &fp->caller, 616 sizeof(currPC)); 617 } 618 if (kr != KERN_SUCCESS) 619 break; 620 621 //retrieve the contents of the frame pointer 622 // and advance to the prev stack frame if it's valid 623 prevFP = 0; 624 if (supervisor) { 625 kr = chudxnu_kern_read( 626 &prevFP, 627 (vm_offset_t) &fp->prev, 628 sizeof(prevFP)); 629 } else { 630 kr = chudxnu_task_read( 631 task, 632 &prevFP, 633 (vm_offset_t) &fp->prev, 634 sizeof(prevFP)); 635 } 636 if (prevFP) { 637 buffer[bufferIndex++] = currPC; 638 prevPC = currPC; 639 } 640 if (prevFP < currFP) { 641 break; 642 } else { 643 currFP = prevFP; 644 } 645 } 646 647 // put the stack pointer on the bottom of the backtrace 648 if(!supervisor) { 649 kr = chudxnu_task_read(task, &esp, regs->uesp, sizeof(uint32_t)); 650 if(kr == KERN_SUCCESS) { 651 buffer[bufferIndex++] = esp; 652 } 653 } 654 655 *count = bufferIndex; 656 return KERN_SUCCESS; 657} 658 659