void unwind_stack(void) { struct sigcontext sc; jmp_buf env; /* get current context */ if (0 != setjmp(env)) { perror("setjmp() failed"); exit(-1); } /* set up (partial) sigcontext */ sc.ebp = (unsigned long)env->__jmpbuf[EBP]; sc.esp = (unsigned long)env->__jmpbuf[ESP]; sc.eip = (unsigned long)env->__jmpbuf[EIP]; /* jump current frame */ unwind_frame(&sc); /* stack back trace */ while (sc.eip != 0) { fprintf(stdout, "pc=0x%lx sp=0x%lx bp=0x%lx\n", sc.eip, sc.esp, sc.ebp); unwind_frame(&sc); } }
static struct pt_regs * unwind_get_regs(struct task_struct *tsk) { struct stackframe frame; register unsigned long current_sp asm ("sp"); int found = 0; //unsigned long sc; if (!tsk) tsk = current; printk("tsk = %p,comm=%s,pid=%d,pgd=0x%p\n", tsk , tsk->comm , tsk->pid , tsk->mm->pgd ); if (tsk == current) { frame.fp = (unsigned long)__builtin_frame_address(0); frame.sp = current_sp; frame.lr = (unsigned long)__builtin_return_address(0); frame.pc = (unsigned long)unwind_get_regs; } else { /* task blocked in __switch_to */ frame.fp = thread_saved_fp(tsk); frame.sp = thread_saved_sp(tsk); /* * The function calling __switch_to cannot be a leaf function * so LR is recovered from the stack. */ frame.lr = 0; frame.pc = thread_saved_pc(tsk); } while (1) { int urc; //unsigned long where = frame.pc; urc = unwind_frame(&frame); if (urc < 0) break; //dump_backtrace_entry(where, frame.pc, frame.sp - 4); if( frame.pc == (unsigned long)ret_fast_syscall ){ found = 1; break; } } if( !found ) return NULL; #if 0 //printk("FRAME:sp=0x%lx,pc=0x%lx,lr=0x%lx,fp=0x%lx\n" , frame.sp,frame.pc,frame.lr,frame.fp ); //rk28_printk_mem((unsigned int*)(frame.sp-sizeof(struct pt_regs)),2*sizeof(struct pt_regs)/4+8, NULL ); sc =*( (unsigned long*)(frame.sp-4)); if( sc >= (unsigned long)&_text && sc < (unsigned long)&_end ){ print_symbol("sys call=%s\n",sc ); } #endif return (struct pt_regs *)(frame.sp+8); // 8 for reg r4,r5 as fifth and sixth args. }
void notrace walk_stackframe(struct stackframe *frame, int (*fn)(struct stackframe *, void *), void *data) { while (1) { int ret; if (fn(frame, data)) break; ret = unwind_frame(frame); if (ret < 0) break; } }
void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk) { struct stackframe frame; int skip; pr_debug("%s(regs = %p tsk = %p)\n", __func__, regs, tsk); if (!tsk) tsk = current; if (!try_get_task_stack(tsk)) return; if (tsk == current) { frame.fp = (unsigned long)__builtin_frame_address(0); frame.pc = (unsigned long)dump_backtrace; } else { /* * task blocked in __switch_to */ frame.fp = thread_saved_fp(tsk); frame.pc = thread_saved_pc(tsk); } #ifdef CONFIG_FUNCTION_GRAPH_TRACER frame.graph = 0; #endif skip = !!regs; printk("Call trace:\n"); do { /* skip until specified stack frame */ if (!skip) { dump_backtrace_entry(frame.pc); } else if (frame.fp == regs->regs[29]) { skip = 0; /* * Mostly, this is the case where this function is * called in panic/abort. As exception handler's * stack frame does not contain the corresponding pc * at which an exception has taken place, use regs->pc * instead. */ dump_backtrace_entry(regs->pc); } } while (!unwind_frame(tsk, &frame)); put_task_stack(tsk); }
unsigned long profile_pc(struct pt_regs *regs) { struct stackframe frame; if (!in_lock_functions(regs->ARM_pc)) return regs->ARM_pc; arm_get_current_stackframe(regs, &frame); do { int ret = unwind_frame(&frame); if (ret < 0) return 0; } while (in_lock_functions(frame.pc)); return frame.pc; }
void notrace walk_stackframe(struct stackframe *frame, int (*fn)(struct stackframe *, void *), void *data) { while (1) { int ret; if (fn(frame, data)) break; #if defined(CONFIG_ARM_UNWIND) ret = unwind_frame(frame); #else ret = -1; #endif if (ret < 0) break; } }
unsigned long profile_pc(struct pt_regs *regs) { struct stackframe frame; if (!in_lock_functions(regs->pc)) return regs->pc; frame.fp = regs->regs[29]; frame.sp = regs->sp; frame.pc = regs->pc; do { int ret = unwind_frame(&frame); if (ret < 0) return 0; } while (in_lock_functions(frame.pc)); return frame.pc; }
void aee_dump_backtrace(struct pt_regs *regs, struct task_struct *tsk) { struct stackframe frame; const register unsigned long current_sp asm("sp"); pr_debug("%s(regs = %p tsk = %p)\n", __func__, regs, tsk); if (!tsk) tsk = current; if (regs) { frame.fp = regs->regs[29]; frame.sp = regs->sp; frame.pc = regs->pc; } else if (tsk == current) { frame.fp = (unsigned long)__builtin_frame_address(0); frame.sp = current_sp; frame.pc = (unsigned long)aee_dump_backtrace; } else { /* * task blocked in __switch_to */ frame.fp = thread_saved_fp(tsk); frame.sp = thread_saved_sp(tsk); frame.pc = thread_saved_pc(tsk); } aee_sram_fiq_log("Call trace:\n"); while (1) { unsigned long where = frame.pc; int ret; ret = unwind_frame(&frame); if (ret < 0) break; dump_backtrace_entry(where, frame.sp); } }
void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk) { struct stackframe frame; unsigned long irq_stack_ptr; int skip; pr_debug("%s(regs = %p tsk = %p)\n", __func__, regs, tsk); if (!tsk) tsk = current; if (!try_get_task_stack(tsk)) return; /* * Switching between stacks is valid when tracing current and in * non-preemptible context. */ if (tsk == current && !preemptible()) irq_stack_ptr = IRQ_STACK_PTR(smp_processor_id()); else irq_stack_ptr = 0; if (tsk == current) { frame.fp = (unsigned long)__builtin_frame_address(0); frame.sp = current_stack_pointer; frame.pc = (unsigned long)dump_backtrace; } else { /* * task blocked in __switch_to */ frame.fp = thread_saved_fp(tsk); frame.sp = thread_saved_sp(tsk); frame.pc = thread_saved_pc(tsk); } #ifdef CONFIG_FUNCTION_GRAPH_TRACER frame.graph = tsk->curr_ret_stack; #endif skip = !!regs; printk("Call trace:\n"); while (1) { unsigned long where = frame.pc; unsigned long stack; int ret; /* skip until specified stack frame */ if (!skip) { dump_backtrace_entry(where); } else if (frame.fp == regs->regs[29]) { skip = 0; /* * Mostly, this is the case where this function is * called in panic/abort. As exception handler's * stack frame does not contain the corresponding pc * at which an exception has taken place, use regs->pc * instead. */ dump_backtrace_entry(regs->pc); } ret = unwind_frame(tsk, &frame); if (ret < 0) break; stack = frame.sp; if (in_exception_text(where)) { /* * If we switched to the irq_stack before calling this * exception handler, then the pt_regs will be on the * task stack. The easiest way to tell is if the large * pt_regs would overlap with the end of the irq_stack. */ if (stack < irq_stack_ptr && (stack + sizeof(struct pt_regs)) > irq_stack_ptr) stack = IRQ_STACK_TO_TASK_STACK(irq_stack_ptr); dump_mem("", "Exception stack", stack, stack + sizeof(struct pt_regs)); } } put_task_stack(tsk); }
bool JavaThread::pd_get_top_frame(frame* fr_addr, void* ucontext, bool isInJava, bool makeWalkable) { assert(this->is_Java_thread(), "must be JavaThread"); JavaThread* jt = (JavaThread *)this; if (!isInJava && makeWalkable) { // make_walkable flushes register windows and grabs last_Java_pc // which can not be done if the ucontext sp matches last_Java_sp // stack walking utilities assume last_Java_pc set if marked flushed jt->frame_anchor()->make_walkable(jt); } // If we have a walkable last_Java_frame, then we should use it // even if isInJava == true. It should be more reliable than // ucontext info. if (jt->has_last_Java_frame() && jt->frame_anchor()->walkable()) { *fr_addr = jt->pd_last_frame(); return true; } ucontext_t* uc = (ucontext_t*) ucontext; // At this point, we don't have a walkable last_Java_frame, so // we try to glean some information out of the ucontext. intptr_t* ret_sp; ExtendedPC addr = os::Solaris::fetch_frame_from_ucontext(this, uc, &ret_sp, NULL /* ret_fp only used on Solaris X86 */); if (addr.pc() == NULL || ret_sp == NULL) { // ucontext wasn't useful return false; } #if INCLUDE_CDS if (UseSharedSpaces && MetaspaceShared::is_in_shared_region(addr.pc(), MetaspaceShared::md)) { // In the middle of a trampoline call. Bail out for safety. // This happens rarely so shouldn't affect profiling. return false; } #endif frame ret_frame(ret_sp, frame::unpatchable, addr.pc()); // we were running Java code when SIGPROF came in if (isInJava) { // If the frame we got is safe then it is most certainly valid if (ret_frame.safe_for_sender(jt)) { *fr_addr = ret_frame; return true; } // If it isn't safe then we can try several things to try and get // a good starting point. // // On sparc the frames are almost certainly walkable in the sense // of sp/fp linkages. However because of recycling of windows if // a piece of code does multiple save's where the initial save creates // a real frame with a return pc and the succeeding save's are used to // simply get free registers and have no real pc then the pc linkage on these // "inner" temporary frames will be bogus. // Since there is in general only a nesting level like // this one deep in general we'll try and unwind such an "inner" frame // here ourselves and see if it makes sense frame unwind_frame(ret_frame.fp(), frame::unpatchable, addr.pc()); if (unwind_frame.safe_for_sender(jt)) { *fr_addr = unwind_frame; return true; } // Well that didn't work. Most likely we're toast on this tick // The previous code would try this. I think it is dubious in light // of changes to safe_for_sender and the unwind trick above but // if it gets us a safe frame who wants to argue. // If we have a last_Java_sp, then the SIGPROF signal caught us // right when we were transitioning from _thread_in_Java to a new // JavaThreadState. We use last_Java_sp instead of the sp from // the ucontext since it should be more reliable. if (jt->has_last_Java_frame()) { ret_sp = jt->last_Java_sp(); frame ret_frame2(ret_sp, frame::unpatchable, addr.pc()); if (ret_frame2.safe_for_sender(jt)) { *fr_addr = ret_frame2; return true; } } // This is the best we can do. We will only be able to decode the top frame *fr_addr = ret_frame; return true; } // At this point, we know we weren't running Java code. We might // have a last_Java_sp, but we don't have a walkable frame. // However, we might still be able to construct something useful // if the thread was running native code. if (jt->has_last_Java_frame()) { assert(!jt->frame_anchor()->walkable(), "case covered above"); frame ret_frame(jt->last_Java_sp(), frame::unpatchable, addr.pc()); *fr_addr = ret_frame; return true; } // nothing else to try but what we found initially *fr_addr = ret_frame; return true; }