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