/*
* Copyright 1991-1998 by Open Software Foundation, Inc.
* All Rights Reserved
*
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose and without fee is hereby granted,
* provided that the above copyright notice appears in all copies and
* that both the copyright notice and this permission notice appear in
* supporting documentation.
*
* OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE.
*
* IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
* NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*
* MkLinux
*/
#include <string.h>
#include <mach/boolean.h>
#include <vm/vm_map.h>
#include <kern/thread.h>
#include <kern/task.h>
#include <machine/asm.h>
#include <machine/db_machdep.h>
#include <machine/setjmp.h>
#include <mach/machine.h>
#include <ddb/db_access.h>
#include <ddb/db_sym.h>
#include <ddb/db_variables.h>
#include <ddb/db_command.h>
#include <ddb/db_task_thread.h>
#include <ddb/db_output.h>
extern jmp_buf_t *db_recover;
extern struct ppc_saved_state *saved_state[];
struct ppc_kernel_state ddb_null_kregs;
/*
* Stack trace.
*/
extern vm_offset_t vm_min_inks_addr; /* set by db_clone_symtabXXX */
#define INKSERVER(va) (((vm_offset_t)(va)) >= vm_min_inks_addr)
extern char intstack[];
#define ININTSTACK(va) \
(((vm_offset_t)(va)) >= (((vm_offset_t)&intstack) + \
(cpu_number() * INTSTACK_SIZE)) && \
(((vm_offset_t)(va)) < (((vm_offset_t)&intstack) + \
((cpu_number()+1) * INTSTACK_SIZE))))
#define INKERNELSTACK(va, th) \
(th == THR_ACT_NULL || \
(((vm_offset_t)(va)) >= th->thread->kernel_stack && \
(((vm_offset_t)(va)) < th->thread->kernel_stack + \
KERNEL_STACK_SIZE)) || \
ININTSTACK(va))
struct ppc_frame {
struct ppc_frame *f_frame;
int f_retaddr;
};
#define TRAP 1
#define INTERRUPT 2
#define SYSCALL 3
db_addr_t db_user_trap_symbol_value = 0;
db_addr_t db_kernel_trap_symbol_value = 0;
db_addr_t db_interrupt_symbol_value = 0;
db_addr_t db_return_to_iret_symbol_value = 0;
db_addr_t db_syscall_symbol_value = 0;
boolean_t db_trace_symbols_found = FALSE;
#if 0
struct i386_kregs {
char *name;
int offset;
} i386_kregs[] = {
{ "ebx", (int)(&((struct i386_kernel_state *)0)->k_ebx) },
{ "esp", (int)(&((struct i386_kernel_state *)0)->k_esp) },
{ "ebp", (int)(&((struct i386_kernel_state *)0)->k_ebp) },
{ "edi", (int)(&((struct i386_kernel_state *)0)->k_edi) },
{ "esi", (int)(&((struct i386_kernel_state *)0)->k_esi) },
{ "eip", (int)(&((struct i386_kernel_state *)0)->k_eip) },
{ 0 },
};
/* Forward */
extern int * db_lookup_i386_kreg(
char *name,
int *kregp);
#endif /* 0 */
extern int db_ppc_reg_value(
struct db_variable * vp,
db_expr_t * val,
int flag,
db_var_aux_param_t ap);
extern void db_find_trace_symbols(void);
extern int db_numargs(
struct ppc_frame *fp,
task_t task);
extern db_addr_t db_startargs(
db_addr_t callerp,
task_t task,
int *nargp);
extern void db_nextframe(
struct ppc_frame **lfp,
struct ppc_frame **fp,
db_addr_t *ip,
int frame_type,
thread_act_t thr_act,
db_addr_t link_reg);
extern int _setjmp(
jmp_buf_t * jb);
/*
* Machine register set.
*/
struct db_variable db_regs[] = {
/* XXX "pc" is an alias to "srr0"... */
{ "pc", (int *)&ddb_regs.srr0, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
{ "srr0", (int *)&ddb_regs.srr0, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
{ "srr1", (int *)&ddb_regs.srr1, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
{ "r0", (int *)&ddb_regs.r0, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
{ "r1", (int *)&ddb_regs.r1, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
{ "r2", (int *)&ddb_regs.r2, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
{ "r3", (int *)&ddb_regs.r3, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
{ "r4", (int *)&ddb_regs.r4, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
{ "r5", (int *)&ddb_regs.r5, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
{ "r6", (int *)&ddb_regs.r6, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
{ "r7", (int *)&ddb_regs.r7, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
{ "r8", (int *)&ddb_regs.r8, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
{ "r9", (int *)&ddb_regs.r9, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
{ "r10", (int *)&ddb_regs.r10, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
{ "r11", (int *)&ddb_regs.r11, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
{ "r12", (int *)&ddb_regs.r12, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
{ "r13", (int *)&ddb_regs.r13, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
{ "r14", (int *)&ddb_regs.r14, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
{ "r15", (int *)&ddb_regs.r15, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
{ "r16", (int *)&ddb_regs.r16, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
{ "r17", (int *)&ddb_regs.r17, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
{ "r18", (int *)&ddb_regs.r18, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
{ "r19", (int *)&ddb_regs.r19, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
{ "r20", (int *)&ddb_regs.r20, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
{ "r21", (int *)&ddb_regs.r21, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
{ "r22", (int *)&ddb_regs.r22, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
{ "r23", (int *)&ddb_regs.r23, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
{ "r24", (int *)&ddb_regs.r24, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
{ "r25", (int *)&ddb_regs.r25, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
{ "r26", (int *)&ddb_regs.r26, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
{ "r27", (int *)&ddb_regs.r27, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
{ "r28", (int *)&ddb_regs.r28, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
{ "r29", (int *)&ddb_regs.r29, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
{ "r30", (int *)&ddb_regs.r30, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
{ "r31", (int *)&ddb_regs.r31, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
{ "cr", (int *)&ddb_regs.cr, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
{ "xer", (int *)&ddb_regs.xer, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
{ "lr", (int *)&ddb_regs.lr, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
{ "ctr", (int *)&ddb_regs.ctr, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
{ "mq", (int *)&ddb_regs.mq, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
{ "pad", (int *)&ddb_regs.pad, db_ppc_reg_value, 0, 0, 0, 0, TRUE },
{ "sr_copyin",(int *)&ddb_regs.sr_copyin,db_ppc_reg_value, 0, 0, 0, 0, TRUE },
};
struct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]);
#if 0
int *
db_lookup_i386_kreg(
char *name,
int *kregp)
{
register struct i386_kregs *kp;
for (kp = i386_kregs; kp->name; kp++) {
if (strcmp(name, kp->name) == 0)
return((int *)((int)kregp + kp->offset));
}
return(0);
}
#endif /* 0 */
int
db_ppc_reg_value(
struct db_variable *vp,
db_expr_t *valuep,
int flag,
db_var_aux_param_t ap)
{
extern char etext;
int *dp = 0;
db_expr_t null_reg = 0;
register thread_act_t thr_act = ap->thr_act;
int cpu;
if (db_option(ap->modif, 'u')) {
if (thr_act == THR_ACT_NULL) {
if ((thr_act = current_act()) == THR_ACT_NULL)
db_error("no user registers\n");
}
if (thr_act == current_act()) {
if (IS_USER_TRAP((&ddb_regs), &etext))
dp = vp->valuep;
else if (ININTSTACK(ddb_regs.r1))
db_error("cannot get/set user registers in nested interrupt\n");
}
} else {
if (thr_act == THR_ACT_NULL || thr_act == current_act()) {
dp = vp->valuep;
} else {
if (thr_act->thread &&
!(thr_act->thread->state & TH_STACK_HANDOFF) &&
thr_act->thread->kernel_stack) {
int cpu;
for (cpu = 0; cpu < NCPUS; cpu++) {
if (machine_slot[cpu].running == TRUE &&
cpu_data[cpu].active_thread == thr_act->thread && saved_state[cpu]) {
dp = (int *) (((int)saved_state[cpu]) +
(((int) vp->valuep) -
(int) &ddb_regs));
break;
}
}
#if 0
if (dp == 0 && thr_act && thr_act->thread)
dp = db_lookup_i386_kreg(vp->name,
(int *)(STACK_IKS(thr_act->thread->kernel_stack)));
#endif
if (dp == 0)
dp = &null_reg;
} else if (thr_act->thread &&
(thr_act->thread->state&TH_STACK_HANDOFF)){
/* only PC is valid */
if (vp->valuep == (int *) &ddb_regs.srr0) {
dp = (int *)(&thr_act->thread->continuation);
} else {
dp = &null_reg;
}
}
}
}
if (dp == 0) {
int cpu;
if (!db_option(ap->modif, 'u')) {
for (cpu = 0; cpu < NCPUS; cpu++) {
if (machine_slot[cpu].running == TRUE &&
cpu_data[cpu].active_thread == thr_act->thread && saved_state[cpu]) {
dp = (int *) (((int)saved_state[cpu]) +
(((int) vp->valuep) -
(int) &ddb_regs));
break;
}
}
}
if (dp == 0) {
if (!thr_act || thr_act->mact.pcb == 0)
db_error("no pcb\n");
dp = (int *)((int)(&thr_act->mact.pcb->ss) +
((int)vp->valuep - (int)&ddb_regs));
}
}
if (flag == DB_VAR_SET)
*dp = *valuep;
else
*valuep = *dp;
return(0);
}
void
db_find_trace_symbols(void)
{
db_expr_t value;
boolean_t found_some;
found_some = FALSE;
if (db_value_of_name(CC_SYM_PREFIX "thandler", &value)) {
db_user_trap_symbol_value = (db_addr_t) value;
found_some = TRUE;
}
if (db_value_of_name(CC_SYM_PREFIX "thandler", &value)) {
db_kernel_trap_symbol_value = (db_addr_t) value;
found_some = TRUE;
}
if (db_value_of_name(CC_SYM_PREFIX "ihandler", &value)) {
db_interrupt_symbol_value = (db_addr_t) value;
found_some = TRUE;
}
#if 0
if (db_value_of_name(CC_SYM_PREFIX "return_to_iret", &value)) {
db_return_to_iret_symbol_value = (db_addr_t) value;
found_some = TRUE;
}
#endif
if (db_value_of_name(CC_SYM_PREFIX "thandler", &value)) {
db_syscall_symbol_value = (db_addr_t) value;
found_some = TRUE;
}
if (found_some)
db_trace_symbols_found = TRUE;
}
/*
* Figure out how many arguments were passed into the frame at "fp".
*/
int db_numargs_default = 5;
int
db_numargs(
struct ppc_frame *fp,
task_t task)
{
int *argp;
int inst;
int args;
extern char etext;
#if 0
argp = (int *)db_get_task_value((int)&fp->f_retaddr, 4, FALSE, task);
if (argp < (int *)VM_MIN_KERNEL_ADDRESS || (char *)argp > &etext)
args = db_numargs_default;
else if (!DB_CHECK_ACCESS((int)argp, 4, task))
args = db_numargs_default;
else {
inst = db_get_task_value((int)argp, 4, FALSE, task);
if ((inst & 0xff) == 0x59) /* popl %ecx */
args = 1;
else if ((inst & 0xffff) == 0xc483) /* addl %n, %esp */
args = ((inst >> 16) & 0xff) / 4;
else
args = db_numargs_default;
}
#else
args = db_numargs_default;
#endif
return (args);
}
int db_startargs_maxinst = 10;
db_addr_t
db_startargs(
db_addr_t callerp,
task_t task,
int *nargp)
{
int i;
int *argp;
int inst;
db_addr_t args;
extern char etext;
int narg;
argp = (int *) callerp;
if (argp < (int *)VM_MIN_KERNEL_ADDRESS || (char *)argp > &etext)
args = 0;
else {
args = 0;
for (i = 0; i < db_startargs_maxinst; i++, argp++) {
if (!DB_CHECK_ACCESS((int) argp, 4, task)) {
continue;
}
inst = db_get_task_value((int) argp, 4, FALSE, task);
if ((inst & 0xffff0000) == 0x907f0000 ||
(inst & 0xffff0000) == 0x90610000) {
/* "stw 3,d(31)" or "stw 3,d(1)" */
args = inst & 0xffff;
for (narg = 1; narg < 10; narg++) {
argp++;
if (!DB_CHECK_ACCESS((int) argp, 4,
task)) {
narg = db_numargs_default;
break;
}
inst = db_get_task_value((int) argp,
4, FALSE,
task);
if ((inst & 0xffff0000) ==
(0x907f0000 + (narg << 21)) ||
(inst & 0xffff0000) ==
(0x90610000 + (narg << 21))) {
continue;
}
break;
}
*nargp = narg;
return args;
}
}
}
return args;
}
#if 0
struct interrupt_frame {
struct i386_frame *if_frame; /* point to next frame */
int if_retaddr; /* return address to _interrupt */
int if_unit; /* unit number */
int if_spl; /* saved spl */
int if_iretaddr; /* _return_to_{iret,iret_i} */
int if_edx; /* old sp(iret) or saved edx(iret_i) */
int if_ecx; /* saved ecx(iret_i) */
int if_eax; /* saved eax(iret_i) */
int if_eip; /* saved eip(iret_i) */
int if_cs; /* saved cs(iret_i) */
int if_efl; /* saved efl(iret_i) */
};
#endif
/*
* Figure out the next frame up in the call stack.
* For trap(), we print the address of the faulting instruction and
* proceed with the calling frame. We return the ip that faulted.
* If the trap was caused by jumping through a bogus pointer, then
* the next line in the backtrace will list some random function as
* being called. It should get the argument list correct, though.
* It might be possible to dig out from the next frame up the name
* of the function that faulted, but that could get hairy.
*/
void
db_nextframe(
struct ppc_frame **lfp, /* in/out */
struct ppc_frame **fp, /* in/out */
db_addr_t *ip, /* out */
int frame_type, /* in */
thread_act_t thr_act,
db_addr_t link_reg) /* in */
{
extern char * trap_type[];
extern int TRAP_TYPES;
struct ppc_saved_state *saved_regs;
#if 0
struct interrupt_frame *ifp;
struct i386_interrupt_state *isp;
#endif
task_t task = (thr_act != THR_ACT_NULL)? thr_act->task: TASK_NULL;
switch(frame_type) {
case TRAP:
#if 0
/*
* We know that trap() has 1 argument and we know that
* it is an (strcut i386_saved_state *).
*/
saved_regs = (struct i386_saved_state *)
db_get_task_value((int)&((*fp)->f_arg0),4,FALSE,task);
if (saved_regs->trapno >= 0 && saved_regs->trapno < TRAP_TYPES) {
db_printf(">>>>> %s trap at ",
trap_type[saved_regs->trapno]);
} else {
db_printf(">>>>> trap (number %d) at ",
saved_regs->trapno & 0xffff);
}
db_task_printsym(saved_regs->eip, DB_STGY_PROC, task);
db_printf(" <<<<<\n");
*fp = (struct i386_frame *)saved_regs->ebp;
*ip = (db_addr_t)saved_regs->eip;
#else
db_printf(">>>>> trap <<<<<\n");
goto miss_frame;
#endif
break;
case INTERRUPT:
if (*lfp == 0) {
db_printf(">>>>> interrupt <<<<<\n");
goto miss_frame;
}
#if 0
db_printf(">>>>> interrupt at ");
ifp = (struct interrupt_frame *)(*lfp);
*fp = ifp->if_frame;
if (ifp->if_iretaddr == db_return_to_iret_symbol_value)
*ip = ((struct i386_interrupt_state *) ifp->if_edx)->eip;
else
*ip = (db_addr_t) ifp->if_eip;
db_task_printsym(*ip, DB_STGY_PROC, task);
db_printf(" <<<<<\n");
#else
db_printf(">>>>> interrupt <<<<<\n");
goto miss_frame;
#endif
break;
case SYSCALL:
if (thr_act != THR_ACT_NULL && thr_act->mact.pcb) {
*ip = (db_addr_t) thr_act->mact.pcb->ss.srr0;
*fp = (struct ppc_frame *) (thr_act->mact.pcb->ss.r1);
break;
}
/* falling down for unknown case */
default:
miss_frame:
if (link_reg)
*ip = link_reg;
else
*ip = (db_addr_t)
db_get_task_value((int)&(*fp)->f_retaddr,
4, FALSE, task);
*lfp = *fp;
*fp = (struct ppc_frame *)
db_get_task_value((int)&(*fp)->f_frame, 4, FALSE, task);
break;
}
}
void
db_stack_trace_cmd(
db_expr_t addr,
boolean_t have_addr,
db_expr_t count,
char *modif)
{
struct ppc_frame *frame, *lastframe;
int *argp;
db_addr_t callpc, lastcallpc;
int frame_type;
boolean_t kernel_only = TRUE;
boolean_t trace_thread = FALSE;
boolean_t trace_all_threads = FALSE;
int thcount = 0;
char *filename;
int linenum;
task_t task;
thread_act_t th, top_act;
int user_frame;
int frame_count;
jmp_buf_t *prev;
jmp_buf_t db_jmp_buf;
queue_entry_t act_list;
db_addr_t link_reg;
if (!db_trace_symbols_found)
db_find_trace_symbols();
{
register char *cp = modif;
register char c;
while ((c = *cp++) != 0) {
if (c == 't')
trace_thread = TRUE;
if (c == 'T') {
trace_all_threads = TRUE;
trace_thread = TRUE;
}
if (c == 'u')
kernel_only = FALSE;
}
}
if (trace_all_threads) {
if (!have_addr && !trace_thread) {
have_addr = TRUE;
trace_thread = TRUE;
act_list = &(current_task()->thr_acts);
addr = (db_expr_t) queue_first(act_list);
} else if (trace_thread) {
if (have_addr) {
if (!db_check_act_address_valid((thread_act_t)addr)) {
if (db_lookup_task((task_t)addr) == -1)
return;
act_list = &(((task_t)addr)->thr_acts);
addr = (db_expr_t) queue_first(act_list);
} else {
act_list = &(((thread_act_t)addr)->task->thr_acts);
thcount = db_lookup_task_act(((thread_act_t)addr)->task,
(thread_act_t)addr);
}
} else {
th = db_default_act;
if (th == THR_ACT_NULL)
th = current_act();
if (th == THR_ACT_NULL) {
db_printf("no active thr_act\n");
return;
}
have_addr = TRUE;
act_list = &th->task->thr_acts;
addr = (db_expr_t) queue_first(act_list);
}
}
}
if (count == -1)
count = 65535;
next_thread:
top_act = THR_ACT_NULL;
user_frame = 0;
frame_count = count;
if (!have_addr && !trace_thread) {
frame = (struct ppc_frame *)(ddb_regs.r1);
callpc = (db_addr_t)ddb_regs.srr0;
link_reg = (db_addr_t)ddb_regs.lr;
th = current_act();
task = (th != THR_ACT_NULL)? th->task: TASK_NULL;
} else if (trace_thread) {
if (have_addr) {
th = (thread_act_t) addr;
if (!db_check_act_address_valid(th))
return;
} else {
th = db_default_act;
if (th == THR_ACT_NULL)
th = current_act();
if (th == THR_ACT_NULL) {
db_printf("no active thread\n");
return;
}
}
if (trace_all_threads)
db_printf("---------- Thread 0x%x (#%d of %d) ----------\n",
addr, thcount, th->task->thr_act_count);
next_activation:
user_frame = 0;
task = th->task;
if (th == current_act()) {
frame = (struct ppc_frame *)(ddb_regs.r1);
callpc = (db_addr_t)ddb_regs.srr0;
link_reg = (db_addr_t)ddb_regs.lr;
} else {
if (th->mact.pcb == 0) {
db_printf("thread has no pcb\n");
return;
}
if (!th->thread) {
register struct ppc_saved_state *pss =
&th->mact.pcb->ss;
db_printf("thread has no shuttle\n");
#if 0
frame = (struct ppc_frame *) (pss->r1);
callpc = (db_addr_t) (pss->srr0);
link_reg = (db_addr_t) (pss->lr);
#else
goto thread_done;
#endif
}
else if ((th->thread->state & TH_STACK_HANDOFF) ||
th->thread->kernel_stack == 0) {
register struct ppc_saved_state *pss =
&th->mact.pcb->ss;
db_printf("Continuation ");
db_task_printsym((db_expr_t)th->thread->continuation,
DB_STGY_PROC, task);
db_printf("\n");
frame = (struct ppc_frame *) (pss->r1);
callpc = (db_addr_t) (pss->srr0);
link_reg = (db_addr_t) (pss->lr);
} else {
int cpu;
for (cpu = 0; cpu < NCPUS; cpu++) {
if (machine_slot[cpu].running == TRUE &&
cpu_data[cpu].active_thread == th->thread &&
saved_state[cpu]) {
break;
}
}
if (top_act != THR_ACT_NULL) {
/*
* Trying to get the backtrace of an activation
* which is not the top_most one in the RPC chain:
* use the activation's pcb.
*/
register struct ppc_saved_state *pss =
&th->mact.pcb->ss;
frame = (struct ppc_frame *) (pss->r1);
callpc = (db_addr_t) (pss->srr0);
link_reg = (db_addr_t) (pss->lr);
} else {
if (cpu == NCPUS) {
register struct ppc_kernel_state *iks;
int r;
iks = STACK_IKS(th->thread->kernel_stack);
prev = db_recover;
if ((r = _setjmp(db_recover = &db_jmp_buf)) == 0) {
frame = (struct ppc_frame *) (iks->r1);
callpc = (db_addr_t) (iks->lr);
link_reg = 0;
} else {
/*
* The kernel stack has probably been
* paged out (swapped out activation).
*/
db_recover = prev;
if (r == 2) /* 'q' from db_more() */
db_error(0);
db_printf("<kernel stack (0x%x) error "
"(probably swapped out)>\n",
iks);
goto next_act;
}
db_recover = prev;
} else {
db_printf(">>>>> active on cpu %d <<<<<\n",
cpu);
frame = (struct ppc_frame *)
(saved_state[cpu]->r1);
callpc = (db_addr_t) saved_state[cpu]->srr0;
link_reg = (db_addr_t) saved_state[cpu]->lr;
}
}
}
}
} else {
frame = (struct ppc_frame *)addr;
th = (db_default_act)? db_default_act: current_act();
task = (th != THR_ACT_NULL)? th->task: TASK_NULL;
callpc = (db_addr_t)db_get_task_value((int)&frame->f_retaddr,
4,
FALSE,
(user_frame) ? task : 0);
link_reg = 0;
}
if (!INKERNELSTACK((unsigned)frame, th)) {
db_printf(">>>>> user space <<<<<\n");
if (kernel_only)
goto thread_done;
user_frame++;
} else if (INKSERVER(callpc) && INKSERVER(frame)) {
db_printf(">>>>> INKserver space <<<<<\n");
}
lastframe = 0;
lastcallpc = (db_addr_t) 0;
while (frame_count-- && frame != 0) {
int narg;
char * name;
db_expr_t offset;
db_addr_t call_func = 0;
int r;
db_symbol_values(NULL,
db_search_task_symbol_and_line(
callpc,
DB_STGY_XTRN,
&offset,
&filename,
&linenum,
(user_frame) ? task : 0,
&narg),
&name, (db_expr_t *)&call_func);
if (user_frame == 0) {
if (call_func &&
(call_func == db_user_trap_symbol_value ||
call_func == db_kernel_trap_symbol_value)) {
frame_type = TRAP;
narg = 1;
} else if (call_func &&
call_func == db_interrupt_symbol_value) {
frame_type = INTERRUPT;
goto next_frame;
} else if (call_func &&
call_func == db_syscall_symbol_value) {
frame_type = SYSCALL;
goto next_frame;
} else {
frame_type = 0;
prev = db_recover;
if ((r = _setjmp(db_recover = &db_jmp_buf)) == 0) {
if (narg < 0)
narg = db_numargs(frame,
(user_frame) ? task : 0);
db_recover = prev;
} else {
db_recover = prev;
goto next_act;
}
}
} else {
frame_type = 0;
prev = db_recover;
if ((r = _setjmp(db_recover = &db_jmp_buf)) == 0) {
if (narg < 0)
narg = db_numargs(frame,
(user_frame) ? task : 0);
db_recover = prev;
} else {
db_recover = prev;
goto next_act;
}
}
if (name == 0 || offset > db_maxoff) {
db_printf("0x%x 0x%x(", frame, callpc);
offset = 0;
} else
db_printf("0x%x %s(", frame, name);
prev = db_recover;
if ((r = _setjmp(db_recover = &db_jmp_buf)) == 0) {
argp = (int *) db_startargs((db_addr_t) (callpc-offset),
(user_frame) ? task : 0,
&narg);
db_recover = prev;
} else {
db_recover = prev;
goto next_act;
}
if (argp == 0)
narg = 0;
else if ((int) lastframe == 0)
argp = (int *) ((int) argp + (int) ddb_regs.r1);
else
argp = (int *) ((int) argp + (int) lastframe);
while (narg > 0) {
int value;
prev = db_recover;
if ((r = _setjmp(db_recover = &db_jmp_buf)) == 0) {
value = db_get_task_value((int)argp,
4,
FALSE,
(user_frame) ? task : 0);
} else {
db_recover = prev;
if (r == 2) /* 'q' from db_more() */
db_error(0);
db_printf("... <stack error>)");
if (offset)
db_printf("+%x", offset);
if (filename) {
db_printf(" [%s", filename);
if (linenum > 0)
db_printf(":%d", linenum);
db_printf("]");
}
db_printf("\n");
goto next_act;
}
db_recover = prev;
db_printf("%x", value);
argp++;
if (--narg != 0)
db_printf(",");
}
if (narg < 0)
db_printf("...");
db_printf(")");
if (offset) {
db_printf("+%x", offset);
}
if (filename) {
db_printf(" [%s", filename);
if (linenum > 0)
db_printf(":%d", linenum);
db_printf("]");
}
db_printf("\n");
next_frame:
lastcallpc = callpc;
prev = db_recov