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#include <machine/thread.h> 33 34#include <kern/kern_types.h> 35#include <kern/processor.h> 36#include <kern/thread.h> 37 38#include <vm/vm_map.h> 39#include <vm/pmap.h> 40 41#include <chud/chud_xnu.h> 42#include <chud/chud_xnu_private.h> 43 44#include <i386/proc_reg.h> 45#include <i386/mp_desc.h> 46#include <i386/misc_protos.h> 47 48#if 0 49#pragma mark **** thread state **** 50#endif 51 52__private_extern__ kern_return_t 53chudxnu_thread_get_state( 54 thread_t thread, 55 thread_flavor_t flavor, 56 thread_state_t tstate, 57 mach_msg_type_number_t *count, 58 boolean_t user_only) 59{ 60 if (user_only) { 61 /* We can't get user state for kernel threads */ 62 if (thread->task == kernel_task) 63 return KERN_FAILURE; 64 /* this properly handles deciding whether or not the thread is 64 bit or not */ 65 return machine_thread_get_state(thread, flavor, tstate, count); 66 } else { 67 // i386 machine_thread_get_kern_state() is different from the PPC version which returns 68 // the previous save area - user or kernel - rather than kernel or NULL if no kernel 69 // interrupt state available 70 71 // the real purpose of this branch is the following: 72 // the user doesn't care if the thread states are user or kernel, he 73 // just wants the thread state, so we need to determine the proper one 74 // to return, kernel or user, for the given thread. 75 if(thread == current_thread() && current_cpu_datap()->cpu_int_state) { 76 // the above are conditions where we possibly can read the kernel 77 // state. we still need to determine if this interrupt happened in 78 // kernel or user context 79 if(USER_STATE(thread) == current_cpu_datap()->cpu_int_state && 80 current_cpu_datap()->cpu_interrupt_level == 1) { 81 // interrupt happened in user land 82 return machine_thread_get_state(thread, flavor, tstate, count); 83 } else { 84 // kernel interrupt. 85 return machine_thread_get_kern_state(thread, flavor, tstate, count); 86 } 87 } else { 88 // get the user-mode thread state 89 return machine_thread_get_state(thread, flavor, tstate, count); 90 } 91 } 92} 93 94__private_extern__ kern_return_t 95chudxnu_thread_set_state( 96 thread_t thread, 97 thread_flavor_t flavor, 98 thread_state_t tstate, 99 mach_msg_type_number_t count, 100 boolean_t user_only) 101{ 102#pragma unused (user_only) 103 return machine_thread_set_state(thread, flavor, tstate, count); 104} 105 106#if 0 107#pragma mark **** task memory read/write **** 108#endif 109 110__private_extern__ kern_return_t 111chudxnu_task_read( 112 task_t task, 113 void *kernaddr, 114 uint64_t usraddr, 115 vm_size_t size) 116{ 117 kern_return_t ret = KERN_SUCCESS; 118 boolean_t old_level; 119 120 if(ml_at_interrupt_context()) { 121 return KERN_FAILURE; // Can't look at tasks on interrupt stack 122 } 123 124 /* 125 * pmap layer requires interrupts to be on 126 */ 127 old_level = ml_set_interrupts_enabled(TRUE); 128 129 if(current_task()==task) { 130 131 if(copyin(usraddr, kernaddr, size)) { 132 ret = KERN_FAILURE; 133 } 134 } else { 135 vm_map_t map = get_task_map(task); 136 ret = vm_map_read_user(map, usraddr, kernaddr, size); 137 } 138 139 ml_set_interrupts_enabled(old_level); 140 141 return ret; 142} 143 144__private_extern__ kern_return_t 145chudxnu_task_write( 146 task_t task, 147 uint64_t useraddr, 148 void *kernaddr, 149 vm_size_t size) 150{ 151 kern_return_t ret = KERN_SUCCESS; 152 boolean_t old_level; 153 154 if(ml_at_interrupt_context()) { 155 return KERN_FAILURE; // can't poke into tasks on interrupt stack 156 } 157 158 /* 159 * pmap layer requires interrupts to be on 160 */ 161 old_level = ml_set_interrupts_enabled(TRUE); 162 163 if(current_task()==task) { 164 165 if(copyout(kernaddr, useraddr, size)) { 166 ret = KERN_FAILURE; 167 } 168 } else { 169 vm_map_t map = get_task_map(task); 170 ret = vm_map_write_user(map, kernaddr, useraddr, size); 171 } 172 173 ml_set_interrupts_enabled(old_level); 174 175 return ret; 176} 177 178__private_extern__ kern_return_t 179chudxnu_kern_read(void *dstaddr, vm_offset_t srcaddr, vm_size_t size) 180{ 181 return (ml_nofault_copy(srcaddr, (vm_offset_t) dstaddr, size) == size ? 182 KERN_SUCCESS: KERN_FAILURE); 183} 184 185__private_extern__ kern_return_t 186chudxnu_kern_write( 187 vm_offset_t dstaddr, 188 void *srcaddr, 189 vm_size_t size) 190{ 191 return (ml_nofault_copy((vm_offset_t) srcaddr, dstaddr, size) == size ? 192 KERN_SUCCESS: KERN_FAILURE); 193} 194 195#define VALID_STACK_ADDRESS(supervisor, addr, minKernAddr, maxKernAddr) (supervisor ? (addr>=minKernAddr && addr<=maxKernAddr) : TRUE) 196// don't try to read in the hole 197#define VALID_STACK_ADDRESS64(supervisor, addr, minKernAddr, maxKernAddr) \ 198(supervisor ? ((uint64_t)addr >= minKernAddr && (uint64_t)addr <= maxKernAddr) : \ 199((uint64_t)addr != 0ULL && ((uint64_t)addr <= 0x00007FFFFFFFFFFFULL || (uint64_t)addr >= 0xFFFF800000000000ULL))) 200 201typedef struct _cframe64_t { 202 uint64_t prevFP; // can't use a real pointer here until we're a 64 bit kernel 203 uint64_t caller; 204 uint64_t args[0]; 205}cframe64_t; 206 207 208typedef struct _cframe_t { 209 uint32_t prev; // this is really a user32-space pointer to the previous frame 210 uint32_t caller; 211 uint32_t args[0]; 212} cframe_t; 213 214extern void * find_user_regs(thread_t); 215extern x86_saved_state32_t *find_kern_regs(thread_t); 216 217static kern_return_t do_backtrace32( 218 task_t task, 219 thread_t thread, 220 x86_saved_state32_t *regs, 221 uint64_t *frames, 222 mach_msg_type_number_t *start_idx, 223 mach_msg_type_number_t max_idx, 224 boolean_t supervisor) 225{ 226 uint32_t tmpWord = 0UL; 227 uint64_t currPC = (uint64_t) regs->eip; 228 uint64_t currFP = (uint64_t) regs->ebp; 229 uint64_t prevPC = 0ULL; 230 uint64_t prevFP = 0ULL; 231 uint64_t kernStackMin = thread->kernel_stack; 232 uint64_t kernStackMax = kernStackMin + kernel_stack_size; 233 mach_msg_type_number_t ct = *start_idx; 234 kern_return_t kr = KERN_FAILURE; 235 236 if(ct >= max_idx) 237 return KERN_RESOURCE_SHORTAGE; // no frames traced 238 239 frames[ct++] = chudxnu_vm_unslide(currPC, supervisor); 240 241 // build a backtrace of this 32 bit state. 242 while(VALID_STACK_ADDRESS(supervisor, currFP, kernStackMin, kernStackMax)) { 243 cframe_t *fp = (cframe_t *) (uintptr_t) currFP; 244 245 if(!currFP) { 246 currPC = 0; 247 break; 248 } 249 250 if(ct >= max_idx) { 251 *start_idx = ct; 252 return KERN_RESOURCE_SHORTAGE; 253 } 254 255 /* read our caller */ 256 if(supervisor) { 257 kr = chudxnu_kern_read(&tmpWord, (vm_offset_t) &fp->caller, sizeof(uint32_t)); 258 } else { 259 kr = chudxnu_task_read(task, &tmpWord, (vm_offset_t) &fp->caller, sizeof(uint32_t)); 260 } 261 262 if(kr != KERN_SUCCESS) { 263 currPC = 0ULL; 264 break; 265 } 266 267 currPC = (uint64_t) tmpWord; // promote 32 bit address 268 269 /* 270 * retrive contents of the frame pointer and advance to the next stack 271 * frame if it's valid 272 */ 273 prevFP = 0; 274 if(supervisor) { 275 kr = chudxnu_kern_read(&tmpWord, (vm_offset_t)&fp->prev, sizeof(uint32_t)); 276 } else { 277 kr = chudxnu_task_read(task, &tmpWord, (vm_offset_t)&fp->prev, sizeof(uint32_t)); 278 } 279 prevFP = (uint64_t) tmpWord; // promote 32 bit address 280 281 if(prevFP) { 282 frames[ct++] = chudxnu_vm_unslide(currPC, supervisor); 283 prevPC = currPC; 284 } 285 if(prevFP < currFP) { 286 break; 287 } else { 288 currFP = prevFP; 289 } 290 } 291 292 *start_idx = ct; 293 return KERN_SUCCESS; 294} 295 296static kern_return_t do_backtrace64( 297 task_t task, 298 thread_t thread, 299 x86_saved_state64_t *regs, 300 uint64_t *frames, 301 mach_msg_type_number_t *start_idx, 302 mach_msg_type_number_t max_idx, 303 boolean_t supervisor) 304{ 305 uint64_t currPC = regs->isf.rip; 306 uint64_t currFP = regs->rbp; 307 uint64_t prevPC = 0ULL; 308 uint64_t prevFP = 0ULL; 309 uint64_t kernStackMin = (uint64_t)thread->kernel_stack; 310 uint64_t kernStackMax = (uint64_t)kernStackMin + kernel_stack_size; 311 mach_msg_type_number_t ct = *start_idx; 312 kern_return_t kr = KERN_FAILURE; 313 314 if(*start_idx >= max_idx) 315 return KERN_RESOURCE_SHORTAGE; // no frames traced 316 317 frames[ct++] = chudxnu_vm_unslide(currPC, supervisor); 318 319 // build a backtrace of this 32 bit state. 320 while(VALID_STACK_ADDRESS64(supervisor, currFP, kernStackMin, kernStackMax)) { 321 // this is the address where caller lives in the user thread 322 uint64_t caller = currFP + sizeof(uint64_t); 323 324 if(!currFP) { 325 currPC = 0; 326 break; 327 } 328 329 if(ct >= max_idx) { 330 *start_idx = ct; 331 return KERN_RESOURCE_SHORTAGE; 332 } 333 334 /* read our caller */ 335 if(supervisor) { 336 kr = chudxnu_kern_read(&currPC, (vm_offset_t)caller, sizeof(uint64_t)); 337 } else { 338 kr = chudxnu_task_read(task, &currPC, caller, sizeof(uint64_t)); 339 } 340 341 if(kr != KERN_SUCCESS) { 342 currPC = 0ULL; 343 break; 344 } 345 346 /* 347 * retrive contents of the frame pointer and advance to the next stack 348 * frame if it's valid 349 */ 350 prevFP = 0; 351 if(supervisor) { 352 kr = chudxnu_kern_read(&prevFP, (vm_offset_t)currFP, sizeof(uint64_t)); 353 } else { 354 kr = chudxnu_task_read(task, &prevFP, currFP, sizeof(uint64_t)); 355 } 356 357 if(VALID_STACK_ADDRESS64(supervisor, prevFP, kernStackMin, kernStackMax)) { 358 frames[ct++] = chudxnu_vm_unslide(currPC, supervisor); 359 prevPC = currPC; 360 } 361 if(prevFP < currFP) { 362 break; 363 } else { 364 currFP = prevFP; 365 } 366 } 367 368 *start_idx = ct; 369 return KERN_SUCCESS; 370} 371 372static kern_return_t do_kernel_backtrace( 373 thread_t thread, 374 struct x86_kernel_state *regs, 375 uint64_t *frames, 376 mach_msg_type_number_t *start_idx, 377 mach_msg_type_number_t max_idx) 378{ 379 uint64_t kernStackMin = (uint64_t)thread->kernel_stack; 380 uint64_t kernStackMax = (uint64_t)kernStackMin + kernel_stack_size; 381 mach_msg_type_number_t ct = *start_idx; 382 kern_return_t kr = KERN_FAILURE; 383 384#if __LP64__ 385 uint64_t currPC = 0ULL; 386 uint64_t currFP = 0ULL; 387 uint64_t prevPC = 0ULL; 388 uint64_t prevFP = 0ULL; 389 if(KERN_SUCCESS != chudxnu_kern_read(&currPC, (vm_offset_t)&(regs->k_rip), sizeof(uint64_t))) { 390 return KERN_FAILURE; 391 } 392 if(KERN_SUCCESS != chudxnu_kern_read(&currFP, (vm_offset_t)&(regs->k_rbp), sizeof(uint64_t))) { 393 return KERN_FAILURE; 394 } 395#else 396 uint32_t currPC = 0U; 397 uint32_t currFP = 0U; 398 uint32_t prevPC = 0U; 399 uint32_t prevFP = 0U; 400 if(KERN_SUCCESS != chudxnu_kern_read(&currPC, (vm_offset_t)&(regs->k_eip), sizeof(uint32_t))) { 401 return KERN_FAILURE; 402 } 403 if(KERN_SUCCESS != chudxnu_kern_read(&currFP, (vm_offset_t)&(regs->k_ebp), sizeof(uint32_t))) { 404 return KERN_FAILURE; 405 } 406#endif 407 408 if(*start_idx >= max_idx) 409 return KERN_RESOURCE_SHORTAGE; // no frames traced 410 411 if(!currPC) { 412 return KERN_FAILURE; 413 } 414 415 frames[ct++] = chudxnu_vm_unslide((uint64_t)currPC, 1); 416 417 // build a backtrace of this kernel state 418#if __LP64__ 419 while(VALID_STACK_ADDRESS64(TRUE, currFP, kernStackMin, kernStackMax)) { 420 // this is the address where caller lives in the user thread 421 uint64_t caller = currFP + sizeof(uint64_t); 422#else 423 while(VALID_STACK_ADDRESS(TRUE, currFP, kernStackMin, kernStackMax)) { 424 uint32_t caller = (uint32_t)currFP + sizeof(uint32_t); 425#endif 426 427 if(!currFP || !currPC) { 428 currPC = 0; 429 break; 430 } 431 432 if(ct >= max_idx) { 433 *start_idx = ct; 434 return KERN_RESOURCE_SHORTAGE; 435 } 436 437 /* read our caller */ 438 kr = chudxnu_kern_read(&currPC, (vm_offset_t)caller, sizeof(currPC)); 439 440 if(kr != KERN_SUCCESS || !currPC) { 441 currPC = 0UL; 442 break; 443 } 444 445 /* 446 * retrive contents of the frame pointer and advance to the next stack 447 * frame if it's valid 448 */ 449 prevFP = 0; 450 kr = chudxnu_kern_read(&prevFP, (vm_offset_t)currFP, sizeof(currPC)); 451 452#if __LP64__ 453 if(VALID_STACK_ADDRESS64(TRUE, prevFP, kernStackMin, kernStackMax)) { 454#else 455 if(VALID_STACK_ADDRESS(TRUE, prevFP, kernStackMin, kernStackMax)) { 456#endif 457 frames[ct++] = chudxnu_vm_unslide((uint64_t)currPC, 1); 458 prevPC = currPC; 459 } 460 if(prevFP <= currFP) { 461 break; 462 } else { 463 currFP = prevFP; 464 } 465 } 466 467 *start_idx = ct; 468 return KERN_SUCCESS; 469} 470 471static 472kern_return_t chudxnu_thread_get_callstack64_internal( 473 thread_t thread, 474 uint64_t *callstack, 475 mach_msg_type_number_t *count, 476 boolean_t user_only, 477 boolean_t kern_only) 478{ 479 kern_return_t kr = KERN_FAILURE; 480 task_t task = thread->task; 481 uint64_t currPC = 0ULL; 482 boolean_t supervisor = FALSE; 483 mach_msg_type_number_t bufferIndex = 0; 484 mach_msg_type_number_t bufferMaxIndex = *count; 485 x86_saved_state_t *tagged_regs = NULL; // kernel register state 486 x86_saved_state64_t *regs64 = NULL; 487 x86_saved_state32_t *regs32 = NULL; 488 x86_saved_state32_t *u_regs32 = NULL; 489 x86_saved_state64_t *u_regs64 = NULL; 490 struct x86_kernel_state *kregs = NULL; 491 492 if(ml_at_interrupt_context()) { 493 494 if(user_only) { 495 /* can't backtrace user state on interrupt stack. */ 496 return KERN_FAILURE; 497 } 498 499 /* backtracing at interrupt context? */ 500 if(thread == current_thread() && current_cpu_datap()->cpu_int_state) { 501 /* 502 * Locate the registers for the interrupted thread, assuming it is 503 * current_thread(). 504 */ 505 tagged_regs = current_cpu_datap()->cpu_int_state; 506 507 if(is_saved_state64(tagged_regs)) { 508 /* 64 bit registers */ 509 regs64 = saved_state64(tagged_regs); 510 supervisor = ((regs64->isf.cs & SEL_PL) != SEL_PL_U); 511 } else { 512 /* 32 bit registers */ 513 regs32 = saved_state32(tagged_regs); 514 supervisor = ((regs32->cs & SEL_PL) != SEL_PL_U); 515 } 516 } 517 } 518 519 if(!ml_at_interrupt_context() && kernel_task == task) { 520 521 if(!thread->kernel_stack) { 522 return KERN_FAILURE; 523 } 524 525 // Kernel thread not at interrupt context 526 kregs = (struct x86_kernel_state *)NULL; 527 528 // nofault read of the thread->kernel_stack pointer 529 if(KERN_SUCCESS != chudxnu_kern_read(&kregs, (vm_offset_t)&(thread->kernel_stack), sizeof(void *))) { 530 return KERN_FAILURE; 531 } 532 533 // Adjust to find the saved kernel state 534 kregs = STACK_IKS((vm_offset_t)(uintptr_t)kregs); 535 536 supervisor = TRUE; 537 } else if(!tagged_regs) { 538 /* 539 * not at interrupt context, or tracing a different thread than 540 * current_thread() at interrupt context 541 */ 542 tagged_regs = USER_STATE(thread); 543 if(is_saved_state64(tagged_regs)) { 544 /* 64 bit registers */ 545 regs64 = saved_state64(tagged_regs); 546 supervisor = ((regs64->isf.cs & SEL_PL) != SEL_PL_U); 547 } else { 548 /* 32 bit registers */ 549 regs32 = saved_state32(tagged_regs); 550 supervisor = ((regs32->cs & SEL_PL) != SEL_PL_U); 551 } 552 } 553 554 *count = 0; 555 556 if(supervisor) { 557 // the caller only wants a user callstack. 558 if(user_only) { 559 // bail - we've only got kernel state 560 return KERN_FAILURE; 561 } 562 } else { 563 // regs32(64) is not in supervisor mode. 564 u_regs32 = regs32; 565 u_regs64 = regs64; 566 regs32 = NULL; 567 regs64 = NULL; 568 } 569 570 if (user_only) { 571 /* we only want to backtrace the user mode */ 572 if(!(u_regs32 || u_regs64)) { 573 /* no user state to look at */ 574 return KERN_FAILURE; 575 } 576 } 577 578 /* 579 * Order of preference for top of stack: 580 * 64 bit kernel state (not likely) 581 * 32 bit kernel state 582 * 64 bit user land state 583 * 32 bit user land state 584 */ 585 586 if(kregs) { 587 /* 588 * nofault read of the registers from the kernel stack (as they can 589 * disappear on the fly). 590 */ 591 592#if __LP64__ 593 if(KERN_SUCCESS != chudxnu_kern_read(&currPC, (vm_offset_t)&(kregs->k_rip), sizeof(uint64_t))) { 594 return KERN_FAILURE; 595 } 596#else 597 uint32_t tmp; 598 if(KERN_SUCCESS != chudxnu_kern_read(&tmp, (vm_offset_t)&(kregs->k_eip), sizeof(uint32_t))) { 599 return KERN_FAILURE; 600 } 601 currPC = (uint64_t)tmp; 602#endif 603 } else if(regs64) { 604 currPC = regs64->isf.rip; 605 } else if(regs32) { 606 currPC = (uint64_t) regs32->eip; 607 } else if(u_regs64) { 608 currPC = u_regs64->isf.rip; 609 } else if(u_regs32) { 610 currPC = (uint64_t) u_regs32->eip; 611 } 612 613 if(!currPC) { 614 /* no top of the stack, bail out */ 615 return KERN_FAILURE; 616 } 617 618 bufferIndex = 0; 619 620 if(bufferMaxIndex < 1) { 621 *count = 0; 622 return KERN_RESOURCE_SHORTAGE; 623 } 624 625 /* backtrace kernel */ 626 if(kregs) { 627 addr64_t address = 0ULL; 628 size_t size = 0UL; 629 630 // do the backtrace 631 kr = do_kernel_backtrace(thread, kregs, callstack, &bufferIndex, bufferMaxIndex); 632 633 // and do a nofault read of (r|e)sp 634#if __LP64__ 635 uint64_t rsp = 0ULL; 636 size = sizeof(uint64_t); 637 638 if(KERN_SUCCESS != chudxnu_kern_read(&address, (vm_offset_t)&(kregs->k_rsp), size)) { 639 address = 0ULL; 640 } 641#else 642 uint32_t rsp = 0ULL, tmp = 0ULL; 643 size = sizeof(uint32_t); 644 645 if(KERN_SUCCESS != chudxnu_kern_read(&tmp, (vm_offset_t)&(kregs->k_esp), size)) { 646 address = 0ULL; 647 } else { 648 address = (addr64_t)tmp; 649 } 650#endif 651 652 if(address && KERN_SUCCESS == chudxnu_kern_read(&rsp, (vm_offset_t)address, size) && bufferIndex < bufferMaxIndex) { 653 callstack[bufferIndex++] = (uint64_t)rsp; 654 } 655 } else if(regs64) { 656 uint64_t rsp = 0ULL; 657 658 // backtrace the 64bit side. 659 kr = do_backtrace64(task, thread, regs64, callstack, &bufferIndex, 660 bufferMaxIndex, TRUE); 661 662 if(KERN_SUCCESS == chudxnu_kern_read(&rsp, (vm_offset_t) regs64->isf.rsp, sizeof(uint64_t)) && 663 bufferIndex < bufferMaxIndex) { 664 callstack[bufferIndex++] = rsp; 665 } 666 667 } else if(regs32) { 668 uint32_t esp = 0UL; 669 670 // backtrace the 32bit side. 671 kr = do_backtrace32(task, thread, regs32, callstack, &bufferIndex, 672 bufferMaxIndex, TRUE); 673 674 if(KERN_SUCCESS == chudxnu_kern_read(&esp, (vm_offset_t) regs32->uesp, sizeof(uint32_t)) && 675 bufferIndex < bufferMaxIndex) { 676 callstack[bufferIndex++] = (uint64_t) esp; 677 } 678 } else if(u_regs64 && !kern_only) { 679 /* backtrace user land */ 680 uint64_t rsp = 0ULL; 681 682 kr = do_backtrace64(task, thread, u_regs64, callstack, &bufferIndex, 683 bufferMaxIndex, FALSE); 684 685 if(KERN_SUCCESS == chudxnu_task_read(task, &rsp, (addr64_t) u_regs64->isf.rsp, sizeof(uint64_t)) && 686 bufferIndex < bufferMaxIndex) { 687 callstack[bufferIndex++] = rsp; 688 } 689 690 } else if(u_regs32 && !kern_only) { 691 uint32_t esp = 0UL; 692 693 kr = do_backtrace32(task, thread, u_regs32, callstack, &bufferIndex, 694 bufferMaxIndex, FALSE); 695 696 if(KERN_SUCCESS == chudxnu_task_read(task, &esp, (addr64_t) u_regs32->uesp, sizeof(uint32_t)) && 697 bufferIndex < bufferMaxIndex) { 698 callstack[bufferIndex++] = (uint64_t) esp; 699 } 700 } 701 702 *count = bufferIndex; 703 return kr; 704} 705 706__private_extern__ 707kern_return_t chudxnu_thread_get_callstack64_kperf( 708 thread_t thread, 709 uint64_t *callstack, 710 mach_msg_type_number_t *count, 711 boolean_t is_user) 712{ 713 return chudxnu_thread_get_callstack64_internal(thread, callstack, count, is_user, !is_user); 714} 715 716__private_extern__ 717kern_return_t chudxnu_thread_get_callstack64( 718 thread_t thread, 719 uint64_t *callstack, 720 mach_msg_type_number_t *count, 721 boolean_t user_only) 722{ 723 return chudxnu_thread_get_callstack64_internal(thread, callstack, count, user_only, 0); 724} 725 726