void msm7k_fiq_handler(void) { struct pt_regs ctx_regs; static cpumask_t fiq_cpu_mask; int this_cpu; unsigned long msm_fiq_flags; spin_lock_irqsave(&msm_fiq_lock, msm_fiq_flags); this_cpu = smp_processor_id(); pr_info("%s: Fiq is received on CPU%d\n", __func__, this_cpu); fiq_counter += 1; ctx_regs.ARM_pc = msm_dump_cpu_ctx[this_cpu].fiq_r14; ctx_regs.ARM_lr = msm_dump_cpu_ctx[this_cpu].svc_r14; ctx_regs.ARM_sp = msm_dump_cpu_ctx[this_cpu].svc_r13; ctx_regs.ARM_fp = msm_dump_cpu_ctx[this_cpu].usr_r11; unwind_backtrace(&ctx_regs, current); if (fiq_counter == 1 && (cpu_is_msm8625() || cpu_is_msm8625q())) { cpumask_copy(&fiq_cpu_mask, cpu_online_mask); cpu_clear(this_cpu, fiq_cpu_mask); gic_raise_secure_softirq(&fiq_cpu_mask, GIC_SECURE_SOFT_IRQ); } flush_cache_all(); outer_flush_all(); spin_unlock_irqrestore(&msm_fiq_lock, msm_fiq_flags); return; }
void cf (int i) { struct trace_arg arg = { .size = 100, .cnt = -1 }; void *handle; _Unwind_Reason_Code (*unwind_backtrace) (_Unwind_Trace_Fn, void *); if (i != othervar || thr != 94) { printf ("i %d thr %d\n", i, thr); exit (1); } /* Test if callback function of _Unwind_Backtrace is not called infinitely times. See Bug 18508 or gcc bug "Bug 66303 - runtime.Caller() returns infinitely deep stack frames on s390x.". The go runtime calls backtrace_full() in <gcc-src>/libbacktrace/backtrace.c, which uses _Unwind_Backtrace(). */ handle = dlopen (LIBGCC_S_SO, RTLD_LAZY); if (handle != NULL) { unwind_backtrace = dlsym (handle, "_Unwind_Backtrace"); if (unwind_backtrace != NULL) { unwind_backtrace (backtrace_helper, &arg); assert (arg.cnt != -1 && arg.cnt < 100); } dlclose (handle); } /* Since uc_link below has been set to NULL, setcontext is supposed to terminate the process normally after this function returns. */ } int do_test (void) { if (getcontext (&ucp) != 0) { if (errno == ENOSYS) { puts ("context handling not supported"); return 0; } puts ("getcontext failed"); return 1; } thr = 94; ucp.uc_link = NULL; ucp.uc_stack.ss_sp = st1; ucp.uc_stack.ss_size = sizeof st1; makecontext (&ucp, (void (*) (void)) cf, 1, somevar - 2); if (setcontext (&ucp) != 0) { puts ("setcontext failed"); return 1; } return 2; }
void CallStack::update(int32_t ignoreDepth, int32_t maxDepth) { if (maxDepth > MAX_DEPTH) { maxDepth = MAX_DEPTH; } ssize_t count = unwind_backtrace(mStack, ignoreDepth + 1, maxDepth); mCount = count > 0 ? count : 0; }
/* Called from the FIQ asm handler */ void msm7k_fiq_handler(void) { struct irq_data *d; struct irq_chip *c; struct pt_regs context_regs; pr_info("Fiq is received %s\n", __func__); fiq_counter++; d = irq_get_irq_data(MSM8625_INT_A9_M2A_2); c = irq_data_get_irq_chip(d); c->irq_mask(d); local_irq_disable(); /* Clear the IRQ from the ENABLE_SET */ gic_clear_irq_pending(MSM8625_INT_A9_M2A_2); local_irq_enable(); flush_cache_all(); outer_flush_all(); pr_err("%s msm_dump_cpu_ctx usr_r0:0x%x", __func__, msm_dump_cpu_ctx.usr_r0); pr_err("%s msm_dump_cpu_ctx usr_r0:0x%x usr_r1:0x%x usr_r2:0x%x usr_r3:0x%x usr_r4:0x%x usr_r5:0x%x usr_r6:0x%x usr_r7:0x%x usr_r8:0x%x usr_r9:0x%x usr_r10:0x%x usr_r11:0x%x usr_r12:0x%x usr_r13:0x%x usr_r14:0x%x irq_spsr:0x%x irq_r13:0x%x irq_r14:0x%x svc_spsr:0x%x svc_r13:0x%x svc_r14:0x%x abt_spsr:0x%x abt_r13:0x%x abt_r14:0x%x und_spsr:0x%x und_r13:0x%x und_r14:0x%x fiq_spsr:0x%x fiq_r8:0x%x fiq_r9:0x%x fiq_r10:0x%x fiq_r11:0x%x fiq_r12:0x%x fiq_r13:0x%x fiq_r14:0x%x\n",__func__, msm_dump_cpu_ctx.usr_r0,msm_dump_cpu_ctx.usr_r1,msm_dump_cpu_ctx.usr_r2,msm_dump_cpu_ctx.usr_r3, msm_dump_cpu_ctx.usr_r4, msm_dump_cpu_ctx.usr_r5, msm_dump_cpu_ctx.usr_r6, msm_dump_cpu_ctx.usr_r7, msm_dump_cpu_ctx.usr_r8, msm_dump_cpu_ctx.usr_r9, msm_dump_cpu_ctx.usr_r10, msm_dump_cpu_ctx.usr_r11, msm_dump_cpu_ctx.usr_r12, msm_dump_cpu_ctx.usr_r13, msm_dump_cpu_ctx.usr_r14, msm_dump_cpu_ctx.irq_spsr, msm_dump_cpu_ctx.irq_r13, msm_dump_cpu_ctx.irq_r14, msm_dump_cpu_ctx.svc_spsr, msm_dump_cpu_ctx.svc_r13, msm_dump_cpu_ctx.svc_r14, msm_dump_cpu_ctx.abt_spsr,msm_dump_cpu_ctx.abt_r13, msm_dump_cpu_ctx.abt_r14, msm_dump_cpu_ctx.und_spsr,msm_dump_cpu_ctx.und_r13, msm_dump_cpu_ctx.und_r14, msm_dump_cpu_ctx.fiq_spsr,msm_dump_cpu_ctx.fiq_r8, msm_dump_cpu_ctx.fiq_r9, msm_dump_cpu_ctx.fiq_r10, msm_dump_cpu_ctx.fiq_r11, msm_dump_cpu_ctx.fiq_r12, msm_dump_cpu_ctx.fiq_r13, msm_dump_cpu_ctx.fiq_r14); context_regs.ARM_sp = msm_dump_cpu_ctx.svc_r13; context_regs.ARM_lr = msm_dump_cpu_ctx.svc_r14; context_regs.ARM_fp = msm_dump_cpu_ctx.usr_r11; //for the svc r11 is the same with usr r11 context_regs.ARM_pc = msm_dump_cpu_ctx.svc_r14; //dump_stack(); unwind_backtrace(&context_regs, current); #ifdef CONFIG_SMP trigger_all_cpu_backtrace(); #endif return; }
/* * Perform stack unwinding by using the _Unwind_Backtrace. * * User application that wants to use backtrace needs to be * compiled with -fexceptions option and -rdynamic to get full * symbols printed. */ int backtrace (void **array, int size) { struct trace_arg arg = { .array = array, .size = size, .cnt = -1 }; if (unwind_backtrace == NULL) backtrace_init(); if (size >= 1) unwind_backtrace (backtrace_helper, &arg); return arg.cnt != -1 ? arg.cnt : 0; }
/* Called from the FIQ asm handler */ void msm7k_fiq_handler(void) { struct irq_data *d; struct irq_chip *c; struct pt_regs ctx_regs; pr_info("Fiq is received %s\n", __func__); fiq_counter++; d = irq_get_irq_data(MSM8625_INT_A9_M2A_2); c = irq_data_get_irq_chip(d); c->irq_mask(d); local_irq_disable(); /* Clear the IRQ from the ENABLE_SET */ gic_clear_irq_pending(MSM8625_INT_A9_M2A_2); local_irq_enable(); ctx_regs.ARM_pc = msm_dump_cpu_ctx.fiq_r14; ctx_regs.ARM_lr = msm_dump_cpu_ctx.svc_r14; ctx_regs.ARM_sp = msm_dump_cpu_ctx.svc_r13; ctx_regs.ARM_fp = msm_dump_cpu_ctx.usr_r11; #ifdef CONFIG_SEC_DEBUG do { extern void sec_save_final_context(void); sec_save_final_context(); } while (0); #endif unwind_backtrace(&ctx_regs, current); #ifdef CONFIG_SMP smp_send_all_cpu_backtrace(); #endif flush_cache_all(); outer_flush_all(); return; }
ssize_t unwind_backtrace_thread(pid_t tid, backtrace_frame_t* backtrace, size_t ignore_depth, size_t max_depth) { if (tid == gettid()) { return unwind_backtrace(backtrace, ignore_depth + 1, max_depth); } ALOGV("Unwinding thread %d from thread %d.", tid, gettid()); // TODO: there's no tgkill(2) on Mac OS, so we'd either need the // mach_port_t or the pthread_t rather than the tid. #if defined(CORKSCREW_HAVE_ARCH) && !defined(__APPLE__) struct sigaction act; struct sigaction oact; memset(&act, 0, sizeof(act)); act.sa_sigaction = unwind_backtrace_thread_signal_handler; act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK; sigemptyset(&act.sa_mask); pthread_mutex_lock(&g_unwind_signal_mutex); map_info_t* milist = acquire_my_map_info_list(); ssize_t frames = -1; if (!sigaction(SIGURG, &act, &oact)) { g_unwind_signal_state.map_info_list = milist; g_unwind_signal_state.backtrace = backtrace; g_unwind_signal_state.ignore_depth = ignore_depth; g_unwind_signal_state.max_depth = max_depth; g_unwind_signal_state.returned_frames = 0; android_atomic_release_store(tid, &g_unwind_signal_state.tid_state); // Signal the specific thread that we want to dump. int32_t tid_state = tid; if (tgkill(getpid(), tid, SIGURG)) { ALOGV("Failed to send SIGURG to thread %d.", tid); } else { // Wait for the other thread to start dumping the stack, or time out. int wait_millis = 250; for (;;) { tid_state = android_atomic_acquire_load(&g_unwind_signal_state.tid_state); if (tid_state != tid) { break; } if (wait_millis--) { ALOGV("Waiting for thread %d to start dumping the stack...", tid); usleep(1000); } else { ALOGV("Timed out waiting for thread %d to start dumping the stack.", tid); break; } } } // Try to cancel the dump if it has not started yet. if (tid_state == tid) { if (!android_atomic_acquire_cas(tid, STATE_CANCEL, &g_unwind_signal_state.tid_state)) { ALOGV("Canceled thread %d stack dump.", tid); tid_state = STATE_CANCEL; } else { tid_state = android_atomic_acquire_load(&g_unwind_signal_state.tid_state); } } // Wait indefinitely for the dump to finish or be canceled. // We cannot apply a timeout here because the other thread is accessing state that // is owned by this thread, such as milist. It should not take very // long to take the dump once started. while (tid_state == STATE_DUMPING) { ALOGV("Waiting for thread %d to finish dumping the stack...", tid); usleep(1000); tid_state = android_atomic_acquire_load(&g_unwind_signal_state.tid_state); } if (tid_state == STATE_DONE) { frames = g_unwind_signal_state.returned_frames; } sigaction(SIGURG, &oact, NULL); } release_my_map_info_list(milist); pthread_mutex_unlock(&g_unwind_signal_mutex); return frames; #else return -1; #endif }