1/*
2 * Copyright (c) 2000-2006 Apple Computer, 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 * @OSF_COPYRIGHT@
30 */
31
32#include <string.h>
33
34#include <mach/boolean.h>
35#include <mach/machine.h>
36
37#include <vm/vm_map.h>
38
39#include <kern/thread.h>
40#include <kern/processor.h>
41#include <kern/task.h>
42
43#include <ppc/cpu_internal.h>
44#include <ppc/exception.h>
45
46#include <machine/asm.h>
47#include <machine/db_machdep.h>
48#include <machine/setjmp.h>
49
50#include <ddb/db_access.h>
51#include <ddb/db_sym.h>
52#include <ddb/db_variables.h>
53#include <ddb/db_command.h>
54#include <ddb/db_task_thread.h>
55#include <ddb/db_output.h>
56
57extern jmp_buf_t *db_recover;
58
59struct savearea ddb_null_kregs;
60
61extern vm_offset_t vm_min_inks_addr;	/* set by db_clone_symtabXXX */
62
63#define DB_NUMARGS_MAX	5
64
65#define	INFIXEDSTACK(va)	0							\
66
67#define INKERNELSTACK(va, th) 1
68
69struct db_ppc_frame {
70	struct db_ppc_frame	*f_frame;
71	int			pad1;
72	uint32_t	f_retaddr;
73	int			pad3;
74	int			pad4;
75	int			pad5;
76	uint32_t	f_arg[DB_NUMARGS_MAX];
77};
78
79#define	TRAP		1
80#define	INTERRUPT	2
81#define SYSCALL		3
82
83db_addr_t	db_user_trap_symbol_value = 0;
84db_addr_t	db_kernel_trap_symbol_value = 0;
85db_addr_t	db_interrupt_symbol_value = 0;
86db_addr_t	db_return_to_iret_symbol_value = 0;
87db_addr_t	db_syscall_symbol_value = 0;
88boolean_t	db_trace_symbols_found = FALSE;
89
90static int db_ppc_reg_value(
91			struct db_variable	* vp,
92			db_expr_t		* val,
93			int			flag,
94			db_var_aux_param_t	ap);
95static void db_find_trace_symbols(void);
96static int db_numargs(
97			struct db_ppc_frame	*fp,
98			task_t			task);
99static boolean_t db_find_arg(
100			struct db_ppc_frame	*frame,
101			db_addr_t		calleepc,
102			task_t			task,
103			int			narg,
104			db_addr_t		*arg);
105static void db_nextframe(
106			struct db_ppc_frame	**lfp,
107			struct db_ppc_frame	**fp,
108			db_addr_t		*ip,
109			int			frame_type,
110			thread_act_t		thr_act,
111			db_addr_t		linkpc);
112
113/*
114 * Machine register set.
115 */
116struct db_variable db_regs[] = {
117	/* XXX "pc" is an alias to "srr0"... */
118	{
119		.name = "pc",
120		.valuep = &ddb_regs.save_srr0,
121		.fcn = db_ppc_reg_value,
122		.min_level = 0,
123		.max_level = 0,
124		.low = 0,
125		.high = 0,
126		.hidden_level = TRUE,
127	},
128	{
129		.name = "srr0",
130		.valuep = &ddb_regs.save_srr0,
131		.fcn = db_ppc_reg_value,
132		.min_level = 0,
133		.max_level = 0,
134		.low = 0,
135		.high = 0,
136		.hidden_level = TRUE,
137	},
138	{
139		.name = "srr1",
140		.valuep = &ddb_regs.save_srr1,
141		.fcn = db_ppc_reg_value,
142		.min_level = 0,
143		.max_level = 0,
144		.low = 0,
145		.high = 0,
146		.hidden_level = TRUE,
147	},
148	{
149		.name = "r0",
150		.valuep = &ddb_regs.save_r0,
151		.fcn = db_ppc_reg_value,
152		.min_level = 0,
153		.max_level = 0,
154		.low = 0,
155		.high = 0,
156		.hidden_level = TRUE,
157	},
158	{
159		.name = "r1",
160		.valuep = &ddb_regs.save_r1,
161		.fcn = db_ppc_reg_value,
162		.min_level = 0,
163		.max_level = 0,
164		.low = 0,
165		.high = 0,
166		.hidden_level = TRUE,
167	},
168	{
169		.name = "r2",
170		.valuep = &ddb_regs.save_r2,
171		.fcn = db_ppc_reg_value,
172		.min_level = 0,
173		.max_level = 0,
174		.low = 0,
175		.high = 0,
176		.hidden_level = TRUE,
177	},
178	{
179		.name = "r3",
180		.valuep = &ddb_regs.save_r3,
181		.fcn = db_ppc_reg_value,
182		.min_level = 0,
183		.max_level = 0,
184		.low = 0,
185		.high = 0,
186		.hidden_level = TRUE,
187	},
188	{
189		.name = "r4",
190		.valuep = &ddb_regs.save_r4,
191		.fcn = db_ppc_reg_value,
192		.min_level = 0,
193		.max_level = 0,
194		.low = 0,
195		.high = 0,
196		.hidden_level = TRUE,
197	},
198	{
199		.name = "r5",
200		.valuep = &ddb_regs.save_r5,
201		.fcn = db_ppc_reg_value,
202		.min_level = 0,
203		.max_level = 0,
204		.low = 0,
205		.high = 0,
206		.hidden_level = TRUE,
207	},
208	{
209		.name = "r6",
210		.valuep = &ddb_regs.save_r6,
211		.fcn = db_ppc_reg_value,
212		.min_level = 0,
213		.max_level = 0,
214		.low = 0,
215		.high = 0,
216		.hidden_level = TRUE,
217	},
218	{
219		.name = "r7",
220		.valuep = &ddb_regs.save_r7,
221		.fcn = db_ppc_reg_value,
222		.min_level = 0,
223		.max_level = 0,
224		.low = 0,
225		.high = 0,
226		.hidden_level = TRUE,
227	},
228	{
229		.name = "r8",
230		.valuep = &ddb_regs.save_r8,
231		.fcn = db_ppc_reg_value,
232		.min_level = 0,
233		.max_level = 0,
234		.low = 0,
235		.high = 0,
236		.hidden_level = TRUE,
237	},
238	{
239		.name = "r9",
240		.valuep = &ddb_regs.save_r9,
241		.fcn = db_ppc_reg_value,
242		.min_level = 0,
243		.max_level = 0,
244		.low = 0,
245		.high = 0,
246		.hidden_level = TRUE,
247	},
248	{
249		.name = "r10",
250		.valuep = &ddb_regs.save_r10,
251		.fcn = db_ppc_reg_value,
252		.min_level = 0,
253		.max_level = 0,
254		.low = 0,
255		.high = 0,
256		.hidden_level = TRUE,
257	},
258	{
259		.name = "r11",
260		.valuep = &ddb_regs.save_r11,
261		.fcn = db_ppc_reg_value,
262		.min_level = 0,
263		.max_level = 0,
264		.low = 0,
265		.high = 0,
266		.hidden_level = TRUE,
267	},
268	{
269		.name = "r12",
270		.valuep = &ddb_regs.save_r12,
271		.fcn = db_ppc_reg_value,
272		.min_level = 0,
273		.max_level = 0,
274		.low = 0,
275		.high = 0,
276		.hidden_level = TRUE,
277	},
278	{
279		.name = "r13",
280		.valuep = &ddb_regs.save_r13,
281		.fcn = db_ppc_reg_value,
282		.min_level = 0,
283		.max_level = 0,
284		.low = 0,
285		.high = 0,
286		.hidden_level = TRUE,
287	},
288	{
289		.name = "r14",
290		.valuep = &ddb_regs.save_r14,
291		.fcn = db_ppc_reg_value,
292		.min_level = 0,
293		.max_level = 0,
294		.low = 0,
295		.high = 0,
296		.hidden_level = TRUE,
297	},
298	{
299		.name = "r15",
300		.valuep = &ddb_regs.save_r15,
301		.fcn = db_ppc_reg_value,
302		.min_level = 0,
303		.max_level = 0,
304		.low = 0,
305		.high = 0,
306		.hidden_level = TRUE,
307	},
308	{
309		.name = "r16",
310		.valuep = &ddb_regs.save_r16,
311		.fcn = db_ppc_reg_value,
312		.min_level = 0,
313		.max_level = 0,
314		.low = 0,
315		.high = 0,
316		.hidden_level = TRUE,
317	},
318	{
319		.name = "r17",
320		.valuep = &ddb_regs.save_r17,
321		.fcn = db_ppc_reg_value,
322		.min_level = 0,
323		.max_level = 0,
324		.low = 0,
325		.high = 0,
326		.hidden_level = TRUE,
327	},
328	{
329		.name = "r18",
330		.valuep = &ddb_regs.save_r18,
331		.fcn = db_ppc_reg_value,
332		.min_level = 0,
333		.max_level = 0,
334		.low = 0,
335		.high = 0,
336		.hidden_level = TRUE,
337	},
338	{
339		.name = "r19",
340		.valuep = &ddb_regs.save_r19,
341		.fcn = db_ppc_reg_value,
342		.min_level = 0,
343		.max_level = 0,
344		.low = 0,
345		.high = 0,
346		.hidden_level = TRUE,
347	},
348	{
349		.name = "r20",
350		.valuep = &ddb_regs.save_r20,
351		.fcn = db_ppc_reg_value,
352		.min_level = 0,
353		.max_level = 0,
354		.low = 0,
355		.high = 0,
356		.hidden_level = TRUE,
357	},
358	{
359		.name = "r21",
360		.valuep = &ddb_regs.save_r21,
361		.fcn = db_ppc_reg_value,
362		.min_level = 0,
363		.max_level = 0,
364		.low = 0,
365		.high = 0,
366		.hidden_level = TRUE,
367	},
368	{
369		.name = "r22",
370		.valuep = &ddb_regs.save_r22,
371		.fcn = db_ppc_reg_value,
372		.min_level = 0,
373		.max_level = 0,
374		.low = 0,
375		.high = 0,
376		.hidden_level = TRUE,
377	},
378	{
379		.name = "r23",
380		.valuep = &ddb_regs.save_r23,
381		.fcn = db_ppc_reg_value,
382		.min_level = 0,
383		.max_level = 0,
384		.low = 0,
385		.high = 0,
386		.hidden_level = TRUE,
387	},
388	{
389		.name = "r24",
390		.valuep = &ddb_regs.save_r24,
391		.fcn = db_ppc_reg_value,
392		.min_level = 0,
393		.max_level = 0,
394		.low = 0,
395		.high = 0,
396		.hidden_level = TRUE,
397	},
398	{
399		.name = "r25",
400		.valuep = &ddb_regs.save_r25,
401		.fcn = db_ppc_reg_value,
402		.min_level = 0,
403		.max_level = 0,
404		.low = 0,
405		.high = 0,
406		.hidden_level = TRUE,
407	},
408	{
409		.name = "r26",
410		.valuep = &ddb_regs.save_r26,
411		.fcn = db_ppc_reg_value,
412		.min_level = 0,
413		.max_level = 0,
414		.low = 0,
415		.high = 0,
416		.hidden_level = TRUE,
417	},
418	{
419		.name = "r27",
420		.valuep = &ddb_regs.save_r27,
421		.fcn = db_ppc_reg_value,
422		.min_level = 0,
423		.max_level = 0,
424		.low = 0,
425		.high = 0,
426		.hidden_level = TRUE,
427	},
428	{
429		.name = "r28",
430		.valuep = &ddb_regs.save_r28,
431		.fcn = db_ppc_reg_value,
432		.min_level = 0,
433		.max_level = 0,
434		.low = 0,
435		.high = 0,
436		.hidden_level = TRUE,
437	},
438	{
439		.name = "r29",
440		.valuep = &ddb_regs.save_r29,
441		.fcn = db_ppc_reg_value,
442		.min_level = 0,
443		.max_level = 0,
444		.low = 0,
445		.high = 0,
446		.hidden_level = TRUE,
447	},
448	{
449		.name = "r30",
450		.valuep = &ddb_regs.save_r30,
451		.fcn = db_ppc_reg_value,
452		.min_level = 0,
453		.max_level = 0,
454		.low = 0,
455		.high = 0,
456		.hidden_level = TRUE,
457	},
458	{
459		.name = "r31",
460		.valuep = &ddb_regs.save_r31,
461		.fcn = db_ppc_reg_value,
462		.min_level = 0,
463		.max_level = 0,
464		.low = 0,
465		.high = 0,
466		.hidden_level = TRUE,
467	},
468	{
469		.name = "cr",
470		.valuep = (db_expr_t *)&ddb_regs.save_cr,
471		.fcn = db_ppc_reg_value,
472		.min_level = 0,
473		.max_level = 0,
474		.low = 0,
475		.high = 0,
476		.hidden_level = TRUE,
477	},
478	{
479		.name = "xer",
480		.valuep = &ddb_regs.save_xer,
481		.fcn = db_ppc_reg_value,
482		.min_level = 0,
483		.max_level = 0,
484		.low = 0,
485		.high = 0,
486		.hidden_level = TRUE,
487	},
488	{
489		.name = "lr",
490		.valuep = &ddb_regs.save_lr,
491		.fcn = db_ppc_reg_value,
492		.min_level = 0,
493		.max_level = 0,
494		.low = 0,
495		.high = 0,
496		.hidden_level = TRUE,
497	},
498	{
499		.name = "ctr",
500		.valuep = &ddb_regs.save_ctr,
501		.fcn = db_ppc_reg_value,
502		.min_level = 0,
503		.max_level = 0,
504		.low = 0,
505		.high = 0,
506		.hidden_level = TRUE,
507	},
508};
509struct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]);
510
511int
512db_ppc_reg_value(
513	struct	db_variable	*vp,
514	db_expr_t		*valuep,
515	int			flag,
516	db_var_aux_param_t	ap)
517{
518	db_expr_t *dp = 0;
519	db_expr_t null_reg = 0;
520	uint32_t *dp32;
521	thread_act_t thr_act = ap->thr_act;
522	unsigned int cpu;
523
524	if (db_option(ap->modif, 'u')) {
525		if (thr_act == THR_ACT_NULL) {
526			if ((thr_act = current_thread()) == THR_ACT_NULL)
527				db_error("no user registers\n");
528		}
529		if (thr_act == current_thread()) {
530			if (IS_USER_TRAP((&ddb_regs))) dp = vp->valuep;
531			else if (INFIXEDSTACK(ddb_regs.save_r1))
532				db_error("cannot get/set user registers in nested interrupt\n");
533		}
534	}
535	else {
536		if (thr_act == THR_ACT_NULL || thr_act == current_thread()) {
537			dp = vp->valuep;
538		}
539		else {
540			if (thr_act->kernel_stack) {
541				for (cpu = 0; cpu < real_ncpus; cpu++) {
542					if (cpu_to_processor(cpu)->state == PROCESSOR_RUNNING &&
543							cpu_to_processor(cpu)->active_thread == thr_act &&
544							PerProcTable[cpu].ppe_vaddr->db_saved_state) {
545
546						dp = (db_expr_t)(((uint32_t)(PerProcTable[cpu].ppe_vaddr->db_saved_state)) +
547								(((uint32_t) vp->valuep) -
548								 (uint32_t) &ddb_regs));
549						break;
550					}
551				}
552
553				if (dp == 0)
554					dp = &null_reg;
555			}
556			else {
557				/* only PC is valid */
558				if (vp->valuep == &ddb_regs.save_srr0)
559					dp = (db_expr_t *)&thr_act->continuation;
560				else
561					dp = &null_reg;
562			}
563		}
564	}
565	if (dp == 0) {
566		if (!db_option(ap->modif, 'u')) {
567			for (cpu = 0; cpu < real_ncpus; cpu++) {
568				if (cpu_to_processor(cpu)->state == PROCESSOR_RUNNING &&
569						cpu_to_processor(cpu)->active_thread == thr_act &&
570						PerProcTable[cpu].ppe_vaddr->db_saved_state) {
571					dp = (int *) (((int)(PerProcTable[cpu].ppe_vaddr->db_saved_state)) +
572							(((int) vp->valuep) - (int) &ddb_regs));
573					break;
574				}
575			}
576		}
577		if (dp == 0) {
578			if (!thr_act || thr_act->machine.pcb == 0)
579				db_error("no pcb\n");
580			dp = (int *)((int)thr_act->machine.pcb + ((int)vp->valuep - (int)&ddb_regs));
581		}
582	}
583
584	if(vp->valuep == (db_expr_t *)&ddb_regs.save_cr) {	/* Is this the CR we are doing? */
585		dp32 = (uint32_t *)dp;						/* Make this easier */
586		if (flag == DB_VAR_SET)
587			*dp32 = *valuep;
588		else
589			*valuep = *dp32;
590	}
591	else {											/* Normal 64-bit registers */
592		if (flag == DB_VAR_SET)
593			*dp = *valuep;
594		else
595			*valuep = *(unsigned long long *)dp;
596	}
597
598	return 0;
599}
600
601
602void
603db_find_trace_symbols(void)
604{
605	db_expr_t	value;
606	boolean_t	found_some;
607
608	found_some = FALSE;
609	if (db_value_of_name(CC_SYM_PREFIX "thandler", &value)) {
610		db_user_trap_symbol_value = (db_addr_t) value;
611		found_some = TRUE;
612	}
613	if (db_value_of_name(CC_SYM_PREFIX "thandler", &value)) {
614		db_kernel_trap_symbol_value = (db_addr_t) value;
615		found_some = TRUE;
616	}
617	if (db_value_of_name(CC_SYM_PREFIX "ihandler", &value)) {
618		db_interrupt_symbol_value = (db_addr_t) value;
619		found_some = TRUE;
620	}
621#if 0
622	if (db_value_of_name(CC_SYM_PREFIX "return_to_iret", &value)) {
623		db_return_to_iret_symbol_value = (db_addr_t) value;
624		found_some = TRUE;
625	}
626#endif
627	if (db_value_of_name(CC_SYM_PREFIX "thandler", &value)) {
628		db_syscall_symbol_value = (db_addr_t) value;
629		found_some = TRUE;
630	}
631	if (found_some)
632		db_trace_symbols_found = TRUE;
633}
634
635int
636db_numargs(
637	struct db_ppc_frame	*fp,
638	task_t			task)
639{
640	return DB_NUMARGS_MAX;
641}
642
643boolean_t
644db_find_arg(
645	struct db_ppc_frame 	*fp,
646	db_addr_t		calleepc,
647	task_t			task,
648	int			narg,
649	db_addr_t		*arg)
650{
651	db_addr_t	argp;
652	db_addr_t	calleep;
653	db_addr_t   	offset;
654	int		i;
655	int		inst;
656	char 		*name;
657
658#if	0
659	db_find_task_sym_and_offset(calleepc, &name, &offset, task);
660	calleep = calleepc-offset;
661
662	for (i = 0; calleep < calleepc; i++, calleep++) {
663		if (!DB_CHECK_ACCESS((int) calleep, 4, task)) {
664			continue;
665		}
666		inst = db_get_task_value(calleep, 4, FALSE, task);
667		if ((inst & 0xffff0000) == (0x907f0000 + (narg << 21)) ||
668				(inst & 0xffff0000) == (0x90610000 + (narg << 21))) {
669			argp = (db_addr_t) &(fp->f_arg[narg]);
670			*arg = argp;
671			return TRUE;
672		}
673	}
674#endif
675	return FALSE;
676}
677
678extern int	TRAP_TYPES;
679/*
680 * Figure out the next frame up in the call stack.
681 * For trap(), we print the address of the faulting instruction and
682 *   proceed with the calling frame.  We return the ip that faulted.
683 *   If the trap was caused by jumping through a bogus pointer, then
684 *   the next line in the backtrace will list some random function as
685 *   being called.  It should get the argument list correct, though.
686 *   It might be possible to dig out from the next frame up the name
687 *   of the function that faulted, but that could get hairy.
688 */
689void
690db_nextframe(
691	struct db_ppc_frame	**lfp,		/* in/out */
692	struct db_ppc_frame	**fp,		/* in/out */
693	db_addr_t		*ip,		/* out */
694	int			frame_type,	/* in */
695	thread_act_t		thr_act,
696	db_addr_t		linkpc)		/* in */
697{
698	struct savearea *saved_regs;
699
700	task_t task = (thr_act != THR_ACT_NULL)? thr_act->task: TASK_NULL;
701
702	switch(frame_type) {
703	case TRAP:
704		db_printf(">>>>> trap <<<<<\n");
705		goto miss_frame;
706		break;
707	case INTERRUPT:
708		if (*lfp == 0) {
709			db_printf(">>>>> interrupt <<<<<\n");
710			goto miss_frame;
711		}
712		db_printf(">>>>> interrupt <<<<<\n");
713		goto miss_frame;
714		break;
715	case SYSCALL:
716		if (thr_act != THR_ACT_NULL && thr_act->machine.pcb) {
717			*ip = (db_addr_t) thr_act->machine.pcb->save_srr0;
718			*fp = (struct db_ppc_frame *) (thr_act->machine.pcb->save_r1);
719			break;
720		}
721		/* falling down for unknown case */
722	default:
723miss_frame:
724		if(!pmap_find_phys(kernel_pmap, (addr64_t)*fp)) {	/* Check if this is valid */
725			db_printf("Frame not mapped %08X\n",*fp);		/* Say not found */
726			*fp = 0;										/* Show not found */
727			break;											/* Out of here */
728		}
729
730		if ((*fp)->f_frame)
731			*ip = (db_addr_t)
732				db_get_task_value((int)&(*fp)->f_frame->f_retaddr,
733						4, FALSE, task);
734		else
735			*ip = (db_addr_t)
736				db_get_task_value((int)&(*fp)->f_retaddr,
737						4, FALSE, task);
738
739		*lfp = *fp;
740		*fp = (struct db_ppc_frame *)
741			db_get_task_value((int)&(*fp)->f_frame, 4, FALSE, task);
742		break;
743	}
744}
745
746void
747db_stack_trace_cmd(
748	db_expr_t	addr,
749	boolean_t	have_addr,
750	db_expr_t	count,
751	char		*modif)
752{
753	struct db_ppc_frame *frame, *lastframe;
754	db_addr_t	callpc, linkpc, lastcallpc;
755	int		frame_type;
756	boolean_t	kernel_only = TRUE;
757	boolean_t	trace_thread = FALSE;
758	boolean_t	trace_all_threads = FALSE;
759	int		thcount = 0;
760	char		*filename;
761	int		linenum;
762	task_t		task;
763	thread_act_t	th, top_act;
764	int		user_frame;
765	int		frame_count;
766	jmp_buf_t	*prev;
767	jmp_buf_t	db_jmp_buf;
768	queue_entry_t	act_list;
769
770	if (!db_trace_symbols_found)
771		db_find_trace_symbols();
772	{
773		char *cp = modif;
774		char c;
775
776		while ((c = *cp++) != 0) {
777			if (c == 't')
778				trace_thread = TRUE;
779			if (c == 'T') {
780				trace_all_threads = TRUE;
781				trace_thread = TRUE;
782			}
783			if (c == 'u')
784				kernel_only = FALSE;
785		}
786	}
787
788	if (trace_all_threads) {
789		if (!have_addr && !trace_thread) {
790			have_addr = TRUE;
791			trace_thread = TRUE;
792			act_list = &(current_task()->threads);
793			addr = (db_expr_t) queue_first(act_list);
794		}
795		else if (trace_thread) {
796			if (have_addr) {
797				if (!db_check_act_address_valid((thread_act_t)addr)) {
798					if (db_lookup_task((task_t)addr) == -1)
799						return;
800					act_list = &(((task_t)addr)->threads);
801					addr = (db_expr_t) queue_first(act_list);
802				}
803				else {
804					act_list = &(((thread_act_t)addr)->task->threads);
805					thcount = db_lookup_task_act(((thread_act_t)addr)->task,
806							(thread_act_t)addr);
807				}
808			}
809			else {
810				th = db_default_act;
811				if (th == THR_ACT_NULL)
812					th = current_thread();
813				if (th == THR_ACT_NULL) {
814					db_printf("no active thr_act\n");
815					return;
816				}
817				have_addr = TRUE;
818				act_list = &th->task->threads;
819				addr = (db_expr_t) queue_first(act_list);
820			}
821		}
822	}
823
824	if (count == -1)
825		count = 65535;
826
827next_thread:
828	top_act = THR_ACT_NULL;
829
830	user_frame = 0;
831	frame_count = count;
832
833	if (!have_addr && !trace_thread) {
834		frame = (struct db_ppc_frame *)(ddb_regs.save_r1);
835		callpc = (db_addr_t)ddb_regs.save_srr0;
836		linkpc = (db_addr_t)ddb_regs.save_lr;
837		th = current_thread();
838		task = (th != THR_ACT_NULL)? th->task: TASK_NULL;
839	}
840	else if (trace_thread) {
841		if (have_addr) {
842			th = (thread_act_t) addr;
843			if (!db_check_act_address_valid(th))
844				return;
845		}
846		else {
847			th = db_default_act;
848			if (th == THR_ACT_NULL)
849				th = current_thread();
850			if (th == THR_ACT_NULL) {
851				db_printf("no active thread\n");
852				return;
853			}
854		}
855		if (trace_all_threads)
856			db_printf("---------- Thread 0x%x (#%d of %d) ----------\n",
857					addr, thcount, th->task->thread_count);
858
859next_activation:
860		user_frame = 0;
861
862		task = th->task;
863		if (th == current_thread()) {
864			frame = (struct db_ppc_frame *)(ddb_regs.save_r1);
865			callpc = (db_addr_t)ddb_regs.save_srr0;
866			linkpc = (db_addr_t)ddb_regs.save_lr;
867		}
868		else {
869			if (th->machine.pcb == 0) {
870				db_printf("thread has no pcb\n");
871				goto thread_done;
872			}
873			if (th->kernel_stack == 0) {
874				struct savearea *pss = th->machine.pcb;
875
876				db_printf("Continuation ");
877				db_task_printsym((db_expr_t)th->continuation,
878						DB_STGY_PROC, task);
879				db_printf("\n");
880				frame = (struct db_ppc_frame *) (pss->save_r1);
881				callpc = (db_addr_t) (pss->save_srr0);
882				linkpc = (db_addr_t) (pss->save_lr);
883			}
884			else {
885				int cpu;
886
887				for (cpu = 0; cpu < real_ncpus; cpu++) {
888					if (cpu_to_processor(cpu)->state == PROCESSOR_RUNNING &&
889							cpu_to_processor(cpu)->active_thread == th &&
890							PerProcTable[cpu].ppe_vaddr->db_saved_state) {
891						break;
892					}
893				}
894				if (top_act != THR_ACT_NULL) {
895					/*
896					 * Trying to get the backtrace of an activation
897					 * which is not the top_most one in the RPC chain:
898					 * use the activation's pcb.
899					 */
900					struct savearea *pss;
901
902					pss = th->machine.pcb;
903					frame = (struct db_ppc_frame *) (pss->save_r1);
904					callpc = (db_addr_t) (pss->save_srr0);
905					linkpc = (db_addr_t) (pss->save_lr);
906				} else {
907					if (cpu == real_ncpus) {
908						struct savearea *iks;
909						int r;
910
911						iks = th->machine.pcb;
912						prev = db_recover;
913						if ((r = _setjmp(db_recover = &db_jmp_buf)) == 0) {
914							frame = (struct db_ppc_frame *) (iks->save_r1);
915							callpc = (db_addr_t) (iks->save_lr);
916							linkpc = 0;
917						} else {
918							/*
919							 * The kernel stack has probably been
920							 * paged out (swapped out activation).
921							 */
922							db_recover = prev;
923							if (r == 2)	/* 'q' from db_more() */
924								db_error(0);
925							db_printf("<kernel stack (0x%x) error "
926									"(probably swapped out)>\n",
927									iks);
928							goto next_act;
929						}
930						db_recover = prev;
931					} else {
932						db_printf(">>>>> active on cpu %d <<<<<\n",
933								cpu);
934						frame = (struct db_ppc_frame *)
935							(PerProcTable[cpu].ppe_vaddr->db_saved_state->save_r1);
936						callpc = (db_addr_t) PerProcTable[cpu].ppe_vaddr->db_saved_state->save_srr0;
937						linkpc = (db_addr_t) PerProcTable[cpu].ppe_vaddr->db_saved_state->save_lr;
938					}
939				}
940			}
941		}
942	} else {
943		frame = (struct db_ppc_frame *)addr;
944		th = (db_default_act)? db_default_act: current_thread();
945		task = (th != THR_ACT_NULL)? th->task: TASK_NULL;
946		if (frame->f_frame) {
947			callpc = (db_addr_t)db_get_task_value
948				((int)&frame->f_frame->f_retaddr,
949				 4, FALSE, (user_frame) ? task : 0);
950			callpc = callpc-sizeof(callpc);
951		} else
952			callpc =0;
953		linkpc = 0;
954	}
955
956	if (!INKERNELSTACK((unsigned)frame, th)) {
957		db_printf(">>>>> user space <<<<<\n");
958		if (kernel_only)
959			goto thread_done;
960		user_frame++;
961	}
962
963	lastframe = 0;
964	lastcallpc = (db_addr_t) 0;
965	while (frame_count-- && frame != 0) {
966		int narg = DB_NUMARGS_MAX;
967		int arg;
968		char *	name;
969		db_expr_t	offset;
970		db_addr_t call_func = 0;
971		int r;
972		db_addr_t	off;
973
974		db_symbol_values(NULL,
975				db_search_task_symbol_and_line(
976					callpc, DB_STGY_XTRN, &offset, &filename,
977					&linenum, (user_frame) ? task : 0, &narg),
978				&name, (db_expr_t *)&call_func);
979		if ( name == NULL) {
980			db_find_task_sym_and_offset(callpc,
981					&name, &off, (user_frame) ? task : 0);
982			offset = (db_expr_t) off;
983		}
984
985		if (user_frame == 0) {
986			if (call_func &&
987					(call_func == db_user_trap_symbol_value ||
988					 call_func == db_kernel_trap_symbol_value)) {
989				frame_type = TRAP;
990				narg = 1;
991			} else if (call_func &&
992					call_func == db_interrupt_symbol_value) {
993				frame_type = INTERRUPT;
994				goto next_frame;
995			} else if (call_func &&
996					call_func == db_syscall_symbol_value) {
997				frame_type = SYSCALL;
998				goto next_frame;
999			} else {
1000				frame_type = 0;
1001				prev = db_recover;
1002				if ((r = _setjmp(db_recover = &db_jmp_buf))
1003						== 0) {
1004					if (narg < 0)
1005						narg = db_numargs(frame,
1006								(user_frame) ? task : 0);
1007					db_recover = prev;
1008				} else {
1009					db_recover = prev;
1010					goto next_act;
1011				}
1012			}
1013		} else {
1014			frame_type = 0;
1015			prev = db_recover;
1016			if ((r = _setjmp(db_recover = &db_jmp_buf)) == 0) {
1017				if (narg < 0)
1018					narg = db_numargs(frame,
1019							(user_frame) ? task : 0);
1020				db_recover = prev;
1021			} else {
1022				db_recover = prev;
1023				goto next_act;
1024			}
1025		}
1026
1027		if (name == 0 || offset > db_maxoff) {
1028			db_printf("[%08X]0x%08X(", frame, callpc);
1029		} else {
1030			db_printf("[%08X]%s", frame, name);
1031			if (offset)
1032				db_printf("+%llx", offset);
1033			db_printf("(");
1034		};
1035
1036		narg = db_numargs(frame, (user_frame) ? task : 0);
1037
1038		for (arg = 0; arg < narg; arg++) {
1039			db_addr_t	argp;
1040			int value;
1041			boolean_t found;
1042
1043			prev = db_recover;
1044			if ((r = _setjmp(db_recover = &db_jmp_buf)) == 0) {
1045				found = FALSE;
1046				if (lastframe)
1047					found = db_find_arg(frame, lastframe->f_retaddr,
1048							(user_frame) ? task : 0, arg, &argp);
1049				if (found)
1050					value = db_get_task_value(argp, 4, FALSE,
1051							(user_frame) ? task : 0);
1052			} else {
1053				db_recover = prev;
1054				if (r == 2)	/* 'q' from db_more() */
1055					db_error(0);
1056				db_printf("... <stack error>)");
1057				db_printf("\n");
1058				goto next_act;
1059			}
1060			db_recover = prev;
1061			if (found)
1062				db_printf("%08X", value);
1063			else
1064				db_printf("??");
1065			argp = argp + sizeof(argp);
1066			if (arg < narg-1)
1067				db_printf(",");
1068		}
1069		if (arg != narg)
1070			db_printf("...");
1071		db_printf(")");
1072		db_printf("\n");
1073
1074next_frame:
1075		lastcallpc = callpc;
1076		prev = db_recover;
1077		if ((r = _setjmp(db_recover = &db_jmp_buf)) == 0) {
1078			db_nextframe(&lastframe, &frame, &callpc, frame_type,
1079					(user_frame) ? th : THR_ACT_NULL, linkpc);
1080			callpc = callpc-sizeof(callpc);
1081			db_recover = prev;
1082		} else {
1083			db_recover = prev;
1084			frame = 0;
1085		}
1086		linkpc = 0;
1087
1088		if (frame == 0) {
1089next_act:
1090			/* end of chain */
1091			break;
1092		}
1093		if (!INKERNELSTACK(lastframe, th) ||
1094				!INKERNELSTACK((unsigned)frame, th))
1095			user_frame++;
1096		if (user_frame == 1) {
1097			db_printf(">>>>> user space <<<<<\n");
1098			if (kernel_only)
1099				break;
1100		}
1101
1102		if (frame <= lastframe) {
1103			if ((INKERNELSTACK(lastframe, th) && !INKERNELSTACK(frame, th)))
1104				continue;
1105			db_printf("Bad frame pointer: 0x%x\n", frame);
1106			break;
1107		}
1108	}
1109
1110thread_done:
1111	if (trace_all_threads) {
1112		if (top_act != THR_ACT_NULL)
1113			th = top_act;
1114		th = (thread_act_t) queue_next(&th->task_threads);
1115		if (! queue_end(act_list, (queue_entry_t) th)) {
1116			db_printf("\n");
1117			addr = (db_expr_t) th;
1118			thcount++;
1119			goto next_thread;
1120		}
1121	}
1122}
1123