static void stack_capture(struct stack *st, struct frame *frame) { struct frame *fp; vm_offset_t callpc; stack_zero(st); fp = frame; for (;;) { if (!INKERNEL((vm_offset_t)fp) || !ALIGNED_POINTER(fp, uint64_t)) break; callpc = fp->fr_pc; if (!INKERNEL(callpc)) break; /* Don't bother traversing trap frames. */ if ((callpc > (uint64_t)tl_trap_begin && callpc < (uint64_t)tl_trap_end) || (callpc > (uint64_t)tl_text_begin && callpc < (uint64_t)tl_text_end)) break; if (stack_put(st, callpc) == -1) break; if (v9next_frame(fp) <= fp || v9next_frame(fp) >= frame + KSTACK_PAGES * PAGE_SIZE) break; fp = v9next_frame(fp); } }
static void kgdb_set_proc_cmd (char *arg, int from_tty) { CORE_ADDR addr; struct kthr *thr; if (!arg) error_no_arg ("proc address for the new context"); if (kvm == NULL) error ("only supported for core file target"); addr = (CORE_ADDR) parse_and_eval_address (arg); if (!INKERNEL (addr)) { thr = kgdb_thr_lookup_pid((int)addr); if (thr == NULL) error ("invalid pid"); } else { thr = kgdb_thr_lookup_paddr(addr); if (thr == NULL) error("invalid proc address"); } kgdb_switch_to_thread(thr->tid); }
static struct ksample_stack * stack_capture_kernel(struct thread *thread) { struct ksample_stack *retval = NULL; register_t rbp; struct amd64_frame *frame; size_t depth = 0; static const size_t MAXDEPTH = 4096 / sizeof(vm_offset_t); caddr_t *pcs = NULL; pcs = malloc(sizeof(*pcs) * MAXDEPTH, M_TEMP, M_WAITOK | M_ZERO); if (pcs == NULL) { return NULL; } frame = (struct amd64_frame*)thread->td_pcb->pcb_rbp; rbp = (register_t)frame; while (1) { vm_offset_t callpc; if (!INKERNEL((long)frame)) break; callpc = frame->f_retaddr; if (!INKERNEL(callpc)) break; if (depth > MAXDEPTH) break; pcs[depth++] = (caddr_t)callpc; if (frame->f_frame <= frame || (vm_offset_t)frame->f_frame >= (vm_offset_t)rbp + KSTACK_PAGES * PAGE_SIZE) break; frame = frame->f_frame; } // printf("%s(%d): depth = %u\n", __FUNCTION__, __LINE__, (unsigned int)depth); retval = malloc(sizeof(struct ksample_stack) + depth * sizeof(caddr_t), M_TEMP, M_WAITOK); if (retval) { retval->depth = depth; bcopy(pcs, retval->pcs, depth * sizeof(pcs[0])); } // printf("%s(%d)\n", __FUNCTION__, __LINE__); free(pcs, M_TEMP); return retval; }
setcor() { fcor = datmap.ufd = getfile(corfil,2); if (kernel && fcor != -1 && INKERNEL(filhdr.a_entry)) { struct stat stb; kcore = 1; fstat(fcor, &stb); datmap.b1 = 0; datmap.e1 = -1; if (kernel == 0 && (stb.st_mode & S_IFREG)) datmap.b1 = 0x80000000; lookup("_Sysmap"); sbr = cursym->n_value; lookup("_Syssize"); slr = cursym->n_value; printf("sbr %x slr %x\n", sbr, slr); lookup("_masterpaddr"); physrw(fcor, KVTOPH(cursym->n_value), &masterpcbb, 1); masterpcbb = (masterpcbb&PG_PFNUM)*NBPG; getpcb(); findstackframe(); return; } if (read(fcor, (char *)&u, ctob(UPAGES))!=ctob(UPAGES) || !INUDOT(u.u_pcb.pcb_ksp) || !INSTACK(u.u_pcb.pcb_usp)) { datmap.e1 = MAXFILE; return; } signo = u.u_arg[0]; sigcode = u.u_code; filhdr.a_text = ctob(u.u_tsize); filhdr.a_data = ctob(u.u_dsize); stksiz = ctob(u.u_ssize); switch (filhdr.a_magic) { case OMAGIC: datmap.b1 = 0; datmap.e1 = filhdr.a_text+filhdr.a_data; datmap.f2 = ctob(UPAGES) + datmap.e1; break; case NMAGIC: case ZMAGIC: datmap.b1 = round(filhdr.a_text, PAGSIZ); datmap.e1 = datmap.b1 + filhdr.a_data; datmap.f2 = ctob(UPAGES) + filhdr.a_data; break; } datbas = datmap.b1; datmap.f1 = ctob(UPAGES); datmap.b2 = MAXSTOR - stksiz; datmap.e2 = MAXSTOR; }
void dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes, uint32_t *intrpc) { int depth = 0; register_t sp; vm_offset_t callpc; pc_t caller = (pc_t) solaris_cpu[curcpu].cpu_dtrace_caller; if (intrpc != 0) pcstack[depth++] = (pc_t) intrpc; aframes++; sp = dtrace_getfp(); while (depth < pcstack_limit) { if (!INKERNEL((long) sp)) break; callpc = *(uintptr_t *)(sp + RETURN_OFFSET); if (!INKERNEL(callpc)) break; if (aframes > 0) { aframes--; if ((aframes == 0) && (caller != 0)) { pcstack[depth++] = caller; } } else { pcstack[depth++] = callpc; } sp = *(uintptr_t*)sp; } for (; depth < pcstack_limit; depth++) { pcstack[depth] = 0; } }
db_sym_t db_frame_info(long *frame, db_addr_t callpc, const char **namep, db_expr_t *offp, int *is_trap, int *nargp) { db_expr_t offset; db_sym_t sym; int narg; const char *name; sym = db_search_symbol(callpc, DB_STGY_ANY, &offset); db_symbol_values(sym, &name, NULL); if (sym == (db_sym_t)0) return (db_sym_t)0; *is_trap = NONE; narg = 0; if (INKERNEL((long)frame) && name) { /* * XXX traps should be based off of the Xtrap* * locations rather than on trap, since some traps * (e.g., npxdna) don't go through trap() */ if (!strcmp(name, "trap")) { *is_trap = TRAP; narg = 0; } else if (!strcmp(name, "syscall_plain") || !strcmp(name, "syscall_fancy")) { *is_trap = SYSCALL; narg = 0; } else if (name[0] == 'X') { if (!strncmp(name, "Xintr", 5) || !strncmp(name, "Xresume", 7) || !strncmp(name, "Xstray", 6) || !strncmp(name, "Xhold", 5) || !strncmp(name, "Xrecurse", 8) || !strcmp(name, "Xdoreti") || !strncmp(name, "Xsoft", 5)) { *is_trap = INTERRUPT; narg = 0; } } } if (offp != NULL) *offp = offset; if (nargp != NULL) *nargp = narg; if (namep != NULL) *namep = name; return sym; }
static int dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size) { ASSERT(INKERNEL(kaddr) && kaddr + size >= kaddr); if (uaddr + size > VM_MAXUSER_ADDRESS || uaddr + size < uaddr) { DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); cpu_core[curcpu].cpuc_dtrace_illval = uaddr; return (0); } return (1); }
static void stack_capture(struct stack *st, u_int32_t *frame) { #if !defined(__ARM_EABI__) && !defined(__clang__) vm_offset_t callpc; while (INKERNEL(frame)) { callpc = frame[FR_SCP]; if (stack_put(st, callpc) == -1) break; frame = (u_int32_t *)(frame[FR_RFP]); } #endif }
static void stack_capture(struct stack *st, u_int32_t *frame) { vm_offset_t callpc; stack_zero(st); while (1) { if (!INKERNEL(frame)) break; callpc = frame[FR_SCP]; if (stack_put(st, callpc) == -1) break; frame = (u_int32_t *)(frame[FR_RFP]); } }
int unwind_frame(struct unwind_state *frame) { uint64_t fp; fp = frame->fp; if (!INKERNEL(fp)) return (-1); frame->sp = fp; frame->fp = *(uint64_t *)(fp - 16); frame->pc = *(uint64_t *)(fp - 8) - 4; return (0); }
void dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes, uint32_t *intrpc) { int depth = 0; uintptr_t ebp; struct frame *frame; uintptr_t callpc; pc_t caller = (pc_t) CPU[KeGetCurrentProcessorNumber()].cpu_dtrace_caller; CONTEXT Context; #if defined(__i386__) || !defined(windows) thread_t *td = curthread; if (intrpc != 0) pcstack[depth++] = (pc_t) intrpc; aframes++; ebp = td->ebp; frame = (struct frame *)ebp; while (depth < pcstack_limit) { if ((uintptr_t)frame < td->klimit || (uintptr_t) ((char *) frame - sizeof(struct frame)) >= td->kbase) break; callpc = frame->f_retaddr; if (!INKERNEL(callpc)) break; if (aframes > 0) { aframes--; if ((aframes == 0) && (caller != 0)) { pcstack[depth++] = caller; } } else { pcstack[depth++] = callpc; } frame = frame->f_frame; } #else // windows and amd64 depth += RtlCaptureStackBackTrace(aframes, pcstack_limit, (PVOID) pcstack, NULL); #endif for (; depth < pcstack_limit; depth++) { pcstack[depth] = 0; } }
int pmc_save_kernel_callchain(uintptr_t *cc, int maxsamples, struct trapframe *tf) { int frames = 0; uintptr_t *sp; cc[frames++] = PMC_TRAPFRAME_TO_PC(tf); sp = (uintptr_t *)PMC_TRAPFRAME_TO_FP(tf); for (frames = 1; frames < maxsamples; frames++) { if (!INKERNEL(sp)) break; cc[frames++] = sp[1]; sp = (uintptr_t *)*sp; } return (frames); }
static void kgdb_set_tid_cmd (char *arg, int from_tty) { CORE_ADDR addr; struct kthr *thr; if (!arg) error_no_arg ("TID or thread address for the new context"); addr = (CORE_ADDR) parse_and_eval_address (arg); if (kvm != NULL && INKERNEL (addr)) { thr = kgdb_thr_lookup_taddr(addr); if (thr == NULL) error("invalid thread address"); addr = thr->tid; } kgdb_switch_to_thread(addr); }
int dtrace_getstackdepth(int aframes) { int depth = 0; struct frame *frame; uintptr_t ebp; uintptr_t callpc; thread_t *td = curthread; #if defined(windows) int pcstack_limit = 100; uint64_t pcstack[100]; #endif ebp = td->ebp; frame = (struct frame *)ebp; depth++; #ifdef __amd64 depth += RtlCaptureStackBackTrace(0, pcstack_limit, (PVOID) pcstack, NULL); #else for(;;) { if ((uintptr_t)frame < td->klimit || (uintptr_t) ((char *) frame - sizeof(struct frame)) >= td->kbase) break; depth++; callpc = frame->f_retaddr; if (!INKERNEL(callpc)) break; frame = frame->f_frame; } #endif if (depth < aframes) return 0; else return depth - aframes; }
setsym() { off_t loc; struct exec hdr; register struct nlist *sp; int ssiz; char *strtab; fsym = getfile(symfil, 1); txtmap.ufd = fsym; if (read(fsym, (char *)&hdr, sizeof hdr) != sizeof hdr || N_BADMAG(hdr)) { txtmap.e1 = MAXFILE; return; } filhdr = hdr; loc = filhdr.a_text+filhdr.a_data; txtmap.f1 = txtmap.f2 = N_TXTOFF(filhdr); txtmap.b1 = 0; switch (filhdr.a_magic) { case OMAGIC: txtmap.b1 = txtmap.e1 = 0; txtmap.b2 = datbas = 0; txtmap.e2 = loc; break; case ZMAGIC: case NMAGIC: txtmap.e1 = filhdr.a_text; txtmap.b2 = datbas = round(filhdr.a_text, PAGSIZ); txtmap.e2 = datbas + filhdr.a_data; txtmap.f2 += txtmap.e1; } loc = N_SYMOFF(filhdr); symtab = (struct nlist *) malloc(filhdr.a_syms); esymtab = &symtab[filhdr.a_syms / sizeof (struct nlist)]; if (symtab == NULL) goto nospac; lseek(fsym, loc, L_SET); if (filhdr.a_syms == 0) goto nosymt; /* SHOULD SQUISH OUT STABS HERE!!! */ if (read(fsym, symtab, filhdr.a_syms) != filhdr.a_syms) goto readerr; if (read(fsym, &ssiz, sizeof (ssiz)) != sizeof (ssiz)) goto oldfmt; strtab = (char *) malloc(ssiz); if (strtab == 0) goto nospac; *(int *)strtab = ssiz; ssiz -= sizeof (ssiz); if (read(fsym, strtab + sizeof (ssiz), ssiz) != ssiz) goto readerr; for (sp = symtab; sp < esymtab; sp++) if (sp->n_strx) /* SHOULD PERFORM RANGE CHECK HERE */ sp->n_un.n_name = strtab + sp->n_un.n_strx; nosymt: if (INKERNEL(filhdr.a_entry)) { txtmap.b1 += KERNOFF; txtmap.e1 += KERNOFF; txtmap.b2 += KERNOFF; txtmap.e2 += KERNOFF; } return; readerr: printf("Error reading symbol|string table\n"); exit(1); nospac: printf("Not enough space for symbol|string table\n"); exit(1); oldfmt: printf("Old format a.out - no string table\n"); exit(1); }
void db_stack_trace_print(db_expr_t addr, boolean_t have_addr, db_expr_t count, char *modif, int (*pr)(const char *, ...)) { struct x86_64_frame *frame, *lastframe; long *argp; db_addr_t callpc; int is_trap = 0; boolean_t kernel_only = TRUE; boolean_t trace_thread = FALSE; #if 0 if (!db_trace_symbols_found) db_find_trace_symbols(); #endif { char *cp = modif; char c; while ((c = *cp++) != 0) { if (c == 't') trace_thread = TRUE; if (c == 'u') kernel_only = FALSE; } } if (!have_addr) { frame = (struct x86_64_frame *)ddb_regs.tf_rbp; callpc = (db_addr_t)ddb_regs.tf_rip; } else { #if 0 if (trace_thread) { struct proc *p; struct user *u; struct lwp *l; (*pr)("trace: pid %d ", (int)addr); p = pfind(addr); if (p == NULL) { (*pr)("not found\n"); return; } l = proc_representative_lwp(p); if (!(l->l_flag&L_INMEM)) { (*pr)("swapped out\n"); return; } u = l->l_addr; frame = (struct x86_64_frame *) u->u_pcb.pcb_rbp; (*pr)("at %p\n", frame); } else #endif frame = (struct x86_64_frame *)addr; callpc = (db_addr_t) db_get_value((db_addr_t)&frame->f_retaddr, 8, FALSE); frame = (struct x86_64_frame *)frame->f_frame; } lastframe = 0; while (count && frame != 0) { int narg; char * name; db_expr_t offset; db_sym_t sym; #define MAXNARG 16 char *argnames[MAXNARG], **argnp = NULL; sym = db_search_symbol(callpc, DB_STGY_ANY, &offset); db_symbol_values(sym, &name, NULL); if (lastframe == 0 && sym == NULL) { /* Symbol not found, peek at code */ long instr = db_get_value(callpc, 8, FALSE); offset = 1; if ((instr & 0x00ffffff) == 0x00e58955 || /* enter: pushl %ebp, movl %esp, %ebp */ (instr & 0x0000ffff) == 0x0000e589 /* enter+1: movl %esp, %ebp */) { offset = 0; } } if (INKERNEL(frame) && name) { #ifdef __ELF__ if (!strcmp(name, "trap")) { is_trap = TRAP; } else if (!strcmp(name, "syscall")) { is_trap = SYSCALL; } else if (name[0] == 'X') { if (!strncmp(name, "Xintr", 5) || !strncmp(name, "Xresume", 7) || !strncmp(name, "Xstray", 6) || !strncmp(name, "Xhold", 5) || !strncmp(name, "Xrecurse", 8) || !strcmp(name, "Xdoreti") || !strncmp(name, "Xsoft", 5)) { is_trap = INTERRUPT; } else goto normal; } else goto normal; narg = 0; #else if (!strcmp(name, "_trap")) { is_trap = TRAP; } else if (!strcmp(name, "_syscall")) { is_trap = SYSCALL; } else if (name[0] == '_' && name[1] == 'X') { if (!strncmp(name, "_Xintr", 6) || !strncmp(name, "_Xresume", 8) || !strncmp(name, "_Xstray", 7) || !strncmp(name, "_Xhold", 6) || !strncmp(name, "_Xrecurse", 9) || !strcmp(name, "_Xdoreti") || !strncmp(name, "_Xsoft", 6)) { is_trap = INTERRUPT; } else goto normal; } else goto normal; narg = 0; #endif /* __ELF__ */ } else { normal: is_trap = NONE; narg = MAXNARG; if (db_sym_numargs(sym, &narg, argnames)) argnp = argnames; else narg = db_numargs(frame); } (*pr)("%s(", name); if (lastframe == 0 && offset == 0 && !have_addr) { /* * We have a breakpoint before the frame is set up * Use %esp instead */ argp = &((struct x86_64_frame *)(ddb_regs.tf_rsp-8))->f_arg0; } else { argp = &frame->f_arg0; } while (narg) { if (argnp) (*pr)("%s=", *argnp++); (*pr)("%lx", db_get_value((db_addr_t)argp, 8, FALSE)); argp++; if (--narg != 0) (*pr)(","); } (*pr)(") at "); db_printsym(callpc, DB_STGY_PROC, pr); (*pr)("\n"); if (lastframe == 0 && offset == 0 && !have_addr) { /* Frame really belongs to next callpc */ lastframe = (struct x86_64_frame *)(ddb_regs.tf_rsp-8); callpc = (db_addr_t) db_get_value((db_addr_t)&lastframe->f_retaddr, 8, FALSE); continue; } lastframe = frame; db_nextframe(&frame, &callpc, &frame->f_arg0, is_trap, pr); if (frame == 0) { /* end of chain */ break; } if (INKERNEL(frame)) { /* staying in kernel */ if (frame <= lastframe) { (*pr)("Bad frame pointer: %p\n", frame); break; } } else if (INKERNEL(lastframe)) { /* switch from user to kernel */ if (kernel_only) { (*pr)("end of kernel\n"); break; /* kernel stack only */ } } else { /* in user */ if (frame <= lastframe) { (*pr)("Bad user frame pointer: %p\n", frame); break; } } --count; } (*pr)("end trace frame: 0x%lx, count: %d\n", frame, count); if (count && is_trap != NONE) { db_printsym(callpc, DB_STGY_XTRN, pr); (*pr)(":\n"); } }
void db_stack_trace_print(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif, void (*pr)(const char *, ...)) { struct frame *frame, *prevframe; db_addr_t pc; bool kernel_only = true; bool trace_thread = false; bool lwpaddr = false; const char *cp = modif; char c; if (ddb_cpuinfo == NULL) ddb_cpuinfo = curcpu(); while ((c = *cp++) != 0) { if (c == 'a') { lwpaddr = true; trace_thread = true; } if (c == 't') trace_thread = true; if (c == 'u') kernel_only = false; } if (!have_addr) { frame = (struct frame *)DDB_TF->tf_out[6]; pc = DDB_TF->tf_pc; } else { if (trace_thread) { struct proc *p; struct user *u; struct lwp *l; if (lwpaddr) { l = (struct lwp *)addr; p = l->l_proc; (*pr)("trace: pid %d ", p->p_pid); } else { (*pr)("trace: pid %d ", (int)addr); p = p_find(addr, PFIND_LOCKED); if (p == NULL) { (*pr)("not found\n"); return; } l = LIST_FIRST(&p->p_lwps); KASSERT(l != NULL); } (*pr)("lid %d ", l->l_lid); if ((l->l_flag & LW_INMEM) == 0) { (*pr)("swapped out\n"); return; } u = l->l_addr; frame = (struct frame *)u->u_pcb.pcb_sp; pc = u->u_pcb.pcb_pc; (*pr)("at %p\n", frame); } else { frame = (struct frame *)addr; pc = 0; } } while (count--) { int i; db_expr_t offset; const char *name; db_addr_t prevpc; #define FR(framep,field) (INKERNEL(framep) \ ? (u_int)(framep)->field \ : fuword(&(framep)->field)) /* Fetch return address and arguments frame */ prevpc = (db_addr_t)FR(frame, fr_pc); prevframe = (struct frame *)FR(frame, fr_fp); /* * Switch to frame that contains arguments */ if (prevframe == NULL || (!INKERNEL(prevframe) && kernel_only)) return; if ((ONINTSTACK(frame) && !ONINTSTACK(prevframe)) || (INKERNEL(frame) && !INKERNEL(prevframe))) { /* We're crossing a trap frame; pc = %l1 */ prevpc = (db_addr_t)FR(frame, fr_local[1]); } name = NULL; if (INKERNEL(pc)) db_find_sym_and_offset(pc, &name, &offset); if (name == NULL) (*pr)("0x%lx(", pc); else (*pr)("%s(", name); /* * Print %i0..%i5, hope these still reflect the * actual arguments somewhat... */ for (i = 0; i < 6; i++) (*pr)("0x%x%s", FR(frame, fr_arg[i]), (i < 5) ? ", " : ") at "); if (INKERNEL(prevpc)) db_printsym(prevpc, DB_STGY_PROC, pr); else (*pr)("0x%lx", prevpc); (*pr)("\n"); pc = prevpc; frame = prevframe; } }
size_t md_stack_capture_curthread(caddr_t *pcs, size_t size) { struct trapframe *tf = curthread->td_intr_frame; pmap_t pmap = vmspace_pmap(curthread->td_proc->p_vmspace); size_t num_kstacks = 0, num_ustacks = 0; #if SAMPLE_DEBUG > 2 printf("%s(%d): curthread pid %u, tid %u, name %s\n", __FUNCTION__, __LINE__, curthread->td_proc->p_pid, curthread->td_tid, curthread->td_name); #endif if (tf == NULL) { #if SAMPLE_DEBUG > 5 printf("%s(%d): intr frame is NULL?\n", __FUNCTION__, __LINE__); #endif // tf = curthread->td_frame; /* * I'm not sure what this means. This should be done via interrupt, * so if curthread wasn't interrupted, then I don't think we can get * anything here? Please tell me what I'm doing wrong. */ return 0; } if (!TRAPF_USERMODE(tf)) { // Start with kernel mode unsigned long callpc; struct amd64_frame *frame; frame = (struct amd64_frame*)tf->tf_rbp; while (num_kstacks < size) { if (!INKERNEL((long)frame)) break; callpc = frame->f_retaddr; if (!INKERNEL(callpc)) break; pcs[num_kstacks++] = (caddr_t)callpc; if (frame->f_frame <= frame || (vm_offset_t)frame->f_frame >= (vm_offset_t)tf->tf_rbp + KSTACK_PAGES * PAGE_SIZE) break; frame = frame->f_frame; } tf = curthread->td_frame; } if (TRAPF_USERMODE(tf)) { caddr_t *start_pc = pcs + num_kstacks; struct amd64_frame frame; #if SAMPLE_DEBUG > 3 printf("%s(%d): doing user mode crawl\n", __FUNCTION__, __LINE__); #endif frame.f_frame = (struct amd64_frame*)tf->tf_rbp; if (tf != curthread->td_intr_frame) { start_pc[num_ustacks++] = (caddr_t)tf->tf_rip; } while ((num_kstacks + num_ustacks) < size) { void *bp = frame.f_frame; /* * The calls to GET_WORD replace the non-functional: * copyin_nofault((void*)frame.f_frame, &frame, sizeof(frame)); */ frame.f_frame = (struct amd64_frame*)GET_WORD(pmap, (caddr_t)frame.f_frame); if (frame.f_frame == 0) { #if SAMPLE_DEBUG > 4 printf("%s(%d): %s: frame is 0\n", __FUNCTION__, __LINE__, curthread->td_name); #endif break; } frame.f_retaddr = (long)GET_WORD(pmap, (caddr_t)frame.f_frame + offsetof(struct amd64_frame, f_retaddr)); if (frame.f_retaddr == 0) { #if SAMPLE_DEBUG > 4 printf("%s(%d): %s: retaddr from frame %p is 0\n", __FUNCTION__, __LINE__, curthread->td_name, (void*)frame.f_frame); #endif break; } #if SAMPLE_DEBUG > 2 printf("%s(%d): f_frame = %ld, f_retaddr = %ld\n", __FUNCTION__, __LINE__, (long)frame.f_frame, (long)frame.f_retaddr); #endif start_pc[num_ustacks++] = (caddr_t)frame.f_retaddr; if ((void*)frame.f_frame < bp) { break; } } } else {
void db_stack_trace_print(db_expr_t addr, boolean_t have_addr, db_expr_t count, char *modif, int (*pr)(const char *, ...)) { struct callframe *frame, *lastframe; long *argp, *arg0; db_addr_t callpc; int is_trap = 0; boolean_t kernel_only = TRUE; boolean_t trace_proc = FALSE; { char *cp = modif; char c; while ((c = *cp++) != 0) { if (c == 'p') trace_proc = TRUE; if (c == 'u') kernel_only = FALSE; } } if (!have_addr) { frame = (struct callframe *)ddb_regs.tf_rbp; callpc = (db_addr_t)ddb_regs.tf_rip; } else { if (trace_proc) { struct proc *p = pfind((pid_t)addr); if (p == NULL) { (*pr) ("db_trace.c: process not found\n"); return; } frame = (struct callframe *)p->p_addr->u_pcb.pcb_rbp; } else { frame = (struct callframe *)addr; } callpc = (db_addr_t) db_get_value((db_addr_t)&frame->f_retaddr, 8, FALSE); frame = (struct callframe *)frame->f_frame; } lastframe = 0; while (count && frame != 0) { int narg; char * name; db_expr_t offset; db_sym_t sym; sym = db_search_symbol(callpc, DB_STGY_ANY, &offset); db_symbol_values(sym, &name, NULL); if (lastframe == 0 && sym == NULL) { /* Symbol not found, peek at code */ long instr = db_get_value(callpc, 8, FALSE); offset = 1; if ((instr & 0x00ffffff) == 0x00e58955 || /* enter: pushl %ebp, movl %esp, %ebp */ (instr & 0x0000ffff) == 0x0000e589 /* enter+1: movl %esp, %ebp */) { offset = 0; } } if (INKERNEL(callpc) && name) { if (!strcmp(name, "trap")) { is_trap = TRAP; } else if (!strcmp(name, "ast")) { is_trap = AST; } else if (!strcmp(name, "syscall")) { is_trap = SYSCALL; } else if (name[0] == 'X') { if (!strncmp(name, "Xintr", 5) || !strncmp(name, "Xresume", 7) || !strncmp(name, "Xrecurse", 8) || !strcmp(name, "Xdoreti") || !strncmp(name, "Xsoft", 5)) { is_trap = INTERRUPT; } else goto normal; } else goto normal; narg = 0; } else { normal: is_trap = NONE; narg = db_numargs(frame); } (*pr)("%s(", name); if (lastframe == 0 && offset == 0 && !have_addr) { /* * We have a breakpoint before the frame is set up * Use %rsp instead */ arg0 = &((struct callframe *)(ddb_regs.tf_rsp-8))->f_arg0; } else { arg0 = &frame->f_arg0; } for (argp = arg0; narg > 0; ) { (*pr)("%lx", db_get_value((db_addr_t)argp, 8, FALSE)); argp++; if (--narg != 0) (*pr)(","); } (*pr)(") at "); db_printsym(callpc, DB_STGY_PROC, pr); (*pr)("\n"); if (lastframe == 0 && offset == 0 && !have_addr && !is_trap) { /* Frame really belongs to next callpc */ lastframe = (struct callframe *)(ddb_regs.tf_rsp-8); callpc = (db_addr_t) db_get_value((db_addr_t)&lastframe->f_retaddr, 8, FALSE); continue; } if (is_trap == INTERRUPT) { /* * Interrupt routines don't update %rbp, so it still * points to the frame that was interrupted. Pull * back to just above lastframe so we can find the * trapframe as with syscalls and traps. */ frame = (struct callframe *)&lastframe->f_retaddr; arg0 = &frame->f_arg0; } lastframe = frame; db_nextframe(&frame, &callpc, arg0, is_trap, pr); if (frame == 0) { /* end of chain */ break; } if (INKERNEL(frame)) { /* staying in kernel */ if (frame <= lastframe) { (*pr)("Bad frame pointer: %p\n", frame); break; } } else if (INKERNEL(lastframe)) { /* switch from user to kernel */ if (kernel_only) { (*pr)("end of kernel\n"); break; /* kernel stack only */ } } else { /* in user */ if (frame <= lastframe) { (*pr)("Bad user frame pointer: %p\n", frame); break; } } --count; } (*pr)("end trace frame: 0x%lx, count: %d\n", frame, count); if (count && is_trap != NONE) { db_printsym(callpc, DB_STGY_XTRN, pr); (*pr)(":\n"); } }
void db_stack_trace_print(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif, void (*pr)(const char *, ...)) { long *frame, *lastframe; long *retaddr, *arg0; long *argp; db_addr_t callpc; int is_trap; bool kernel_only = true; bool trace_thread = false; bool lwpaddr = false; #if 0 if (!db_trace_symbols_found) db_find_trace_symbols(); #endif { const char *cp = modif; char c; while ((c = *cp++) != 0) { if (c == 'a') { lwpaddr = true; trace_thread = true; } if (c == 't') trace_thread = true; if (c == 'u') kernel_only = false; } } if (!have_addr) { frame = (long *)ddb_regs.tf_rbp; callpc = (db_addr_t)ddb_regs.tf_rip; } else { if (trace_thread) { struct proc *p; struct user *u; struct lwp *l; if (lwpaddr) { l = (struct lwp *)addr; p = l->l_proc; (*pr)("trace: pid %d ", p->p_pid); } else { (*pr)("trace: pid %d ", (int)addr); p = p_find(addr, PFIND_LOCKED); if (p == NULL) { (*pr)("not found\n"); return; } l = LIST_FIRST(&p->p_lwps); KASSERT(l != NULL); } (*pr)("lid %d ", l->l_lid); if (!(l->l_flag & LW_INMEM)) { (*pr)("swapped out\n"); return; } u = l->l_addr; if (p == curproc && l == curlwp) { frame = (long *)ddb_regs.tf_rbp; callpc = (db_addr_t)ddb_regs.tf_rip; (*pr)("at %p\n", frame); } else { frame = (long *)u->u_pcb.pcb_rbp; callpc = (db_addr_t) db_get_value((long)(frame + 1), 8, false); (*pr)("at %p\n", frame); frame = (long *)*frame; /* XXXfvdl db_get_value? */ } } else { frame = (long *)addr; callpc = (db_addr_t) db_get_value((long)(frame + 1), 8, false); frame = (long *)*frame; /* XXXfvdl db_get_value? */ } } retaddr = frame + 1; arg0 = frame + 2; lastframe = 0; while (count && frame != 0) { int narg; const char * name; db_expr_t offset; db_sym_t sym; char *argnames[16], **argnp = NULL; db_addr_t lastcallpc; name = "?"; is_trap = NONE; offset = 0; sym = db_frame_info(frame, callpc, &name, &offset, &is_trap, &narg); if (lastframe == 0 && sym == (db_sym_t)0) { /* Symbol not found, peek at code */ u_long instr = db_get_value(callpc, 4, false); offset = 1; if (instr == 0xe5894855 || /* enter: pushq %rbp, movq %rsp, %rbp */ (instr & 0x00ffffff) == 0x0048e589 /* enter+1: movq %rsp, %rbp */) { offset = 0; } } if (is_trap == NONE) { if (db_sym_numargs(sym, &narg, argnames)) argnp = argnames; else narg = db_numargs(frame); } (*pr)("%s(", name); if (lastframe == 0 && offset == 0 && !have_addr) { /* * We have a breakpoint before the frame is set up * Use %rsp instead */ argp = &((struct x86_64_frame *)(ddb_regs.tf_rsp-8))->f_arg0; } else { argp = frame + 2; } while (narg) { if (argnp) (*pr)("%s=", *argnp++); (*pr)("%lx", db_get_value((long)argp, 8, false)); argp++; if (--narg != 0) (*pr)(","); } (*pr)(") at "); db_printsym(callpc, DB_STGY_PROC, pr); (*pr)("\n"); if (lastframe == 0 && offset == 0 && !have_addr) { /* Frame really belongs to next callpc */ struct x86_64_frame *fp = (void *)(ddb_regs.tf_rsp-8); lastframe = (long *)fp; callpc = (db_addr_t) db_get_value((db_addr_t)&fp->f_retaddr, 8, false); continue; } lastframe = frame; lastcallpc = callpc; if (!db_nextframe(&frame, &retaddr, &arg0, &callpc, frame + 2, is_trap, pr)) break; if (INKERNEL((long)frame)) { /* staying in kernel */ if (frame < lastframe || (frame == lastframe && callpc == lastcallpc)) { (*pr)("Bad frame pointer: %p\n", frame); break; } } else if (INKERNEL((long)lastframe)) { /* switch from user to kernel */ if (kernel_only) break; /* kernel stack only */ } else { /* in user */ if (frame <= lastframe) { (*pr)("Bad user frame pointer: %p\n", frame); break; } } --count; } if (count && is_trap != NONE) { db_printsym(callpc, DB_STGY_XTRN, pr); (*pr)(":\n"); } }