void tile_backtrace(struct pt_regs *const regs, unsigned int depth) { struct KBacktraceIterator kbt; unsigned int i; /* * Get the address just after the "jalr" instruction that * jumps to the handler for a syscall. When we find this * address in a backtrace, we silently ignore it, which gives * us a one-step backtrace connection from the sys_xxx() * function in the kernel to the xxx() function in libc. * Otherwise, we lose the ability to properly attribute time * from the libc calls to the kernel implementations, since * oprofile only considers PCs from backtraces a pair at a time. */ unsigned long handle_syscall_pc = handle_syscall_link_address(); KBacktraceIterator_init(&kbt, NULL, regs); kbt.profile = 1; /* * The sample for the pc is already recorded. Now we are adding the * address of the callsites on the stack. Our iterator starts * with the frame of the (already sampled) call site. If our * iterator contained a "return address" field, we could have just * used it and wouldn't have needed to skip the first * frame. That's in effect what the arm and x86 versions do. * Instead we peel off the first iteration to get the equivalent * behavior. */ if (KBacktraceIterator_end(&kbt)) return; KBacktraceIterator_next(&kbt); for (i = 0; i < depth; ++i) { int is_kernel; unsigned long pc; if (KBacktraceIterator_end(&kbt)) break; pc = kbt.it.pc; is_kernel = (pc >= PAGE_OFFSET && !is_arch_mappable_range(pc, 1)); if (pc != handle_syscall_pc) oprofile_add_pc(pc, is_kernel, 0); KBacktraceIterator_next(&kbt); } }
/* * This method wraps the backtracer's more generic support. * It is only invoked from the architecture-specific code; show_stack() * and dump_stack() (in entry.S) are architecture-independent entry points. */ void tile_show_stack(struct KBacktraceIterator *kbt, int headers) { int i; if (headers) { /* * Add a blank line since if we are called from panic(), * then bust_spinlocks() spit out a space in front of us * and it will mess up our KERN_ERR. */ pr_err("\n"); pr_err("Starting stack dump of tid %d, pid %d (%s)" " on cpu %d at cycle %lld\n", kbt->task->pid, kbt->task->tgid, kbt->task->comm, smp_processor_id(), get_cycles()); } kbt->verbose = 1; i = 0; for (; !KBacktraceIterator_end(kbt); KBacktraceIterator_next(kbt)) { char *modname; const char *name; unsigned long address = kbt->it.pc; unsigned long offset, size; char namebuf[KSYM_NAME_LEN+100]; if (address >= PAGE_OFFSET) name = kallsyms_lookup(address, &size, &offset, &modname, namebuf); else name = NULL; if (!name) namebuf[0] = '\0'; else { size_t namelen = strlen(namebuf); size_t remaining = (sizeof(namebuf) - 1) - namelen; char *p = namebuf + namelen; int rc = snprintf(p, remaining, "+%#lx/%#lx ", offset, size); if (modname && rc < remaining) snprintf(p + rc, remaining - rc, "[%s] ", modname); namebuf[sizeof(namebuf)-1] = '\0'; } pr_err(" frame %d: 0x%lx %s(sp 0x%lx)\n", i++, address, namebuf, (unsigned long)(kbt->it.sp)); if (i >= 100) { pr_err("Stack dump truncated" " (%d frames)\n", i); break; } } if (kbt->end == KBT_LOOP) pr_err("Stack dump stopped; next frame identical to this one\n"); if (headers) pr_err("Stack dump complete\n"); }
void save_stack_trace_tsk(struct task_struct *task, struct stack_trace *trace) { struct KBacktraceIterator kbt; int skip = trace->skip; int i = 0; if (task == NULL || task == current) KBacktraceIterator_init_current(&kbt); else KBacktraceIterator_init(&kbt, task, NULL); for (; !KBacktraceIterator_end(&kbt); KBacktraceIterator_next(&kbt)) { if (skip) { --skip; continue; } if (i >= trace->max_entries || kbt.it.pc < PAGE_OFFSET) break; trace->entries[i++] = kbt.it.pc; } trace->nr_entries = i; }