/* This recently started being used in arch-independent code too, as in * kernel/sched.c.*/ void show_stack(struct task_struct *task, unsigned long *esp) { unsigned long *stack; int i; if (esp == NULL) { if (task != current && task != NULL) { esp = (unsigned long *) KSTK_ESP(task); } else { esp = (unsigned long *) &esp; } } stack = esp; for(i = 0; i < kstack_depth_to_print; i++) { if (kstack_end(stack)) break; if (i && ((i % 8) == 0)) printk("\n "); printk("%08lx ", *stack++); } printk("Call Trace: \n"); show_trace(task, esp); }
void dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit) { uint64_t *pcstack_end = pcstack + pcstack_limit; volatile uint8_t *flags = (volatile uint8_t *)&cpu_core[cpu_get_id()].cpuc_dtrace_flags; unsigned long *sp; unsigned long *bos; if (*flags & CPU_DTRACE_FAULT) return; if (pcstack_limit <= 0) return; *pcstack++ = (uint64_t)current->pid; if (pcstack >= pcstack_end) return; /***********************************************/ /* Linux provides a built in function which */ /* is good because stack walking is arch */ /* dependent. (save_stack_trace) */ /* */ /* Unfortunately this is options dependent */ /* (CONFIG_STACKTRACE) so we cannot use it. */ /* And its GPL anyhow, so we cannot copy */ /* it. */ /* */ /* Whats worse is that we might be compiled */ /* with a frame pointer (only on x86-32) so */ /* we have three scenarios to handle. */ /***********************************************/ /***********************************************/ /* Ye gods! The world is an awful place to */ /* live. The target process, may or may not */ /* have frame pointers. In fact, some */ /* frames may have it and some may not (eg */ /* different libraries may be compiled */ /* differently). */ /* */ /* Looks like distro owners dont care about */ /* debuggabiity, and give us no frame */ /* pointers. */ /* */ /* This function is really important and */ /* useful. On modern Linux systems, gdb */ /* (and pstack) contain all the smarts. In */ /* fact, pstack is often a wrapper around */ /* gdb - i.e. its so complex we cannot do */ /* this. */ /***********************************************/ /***********************************************/ /* Bear in mind that user stacks can be */ /* megabytes in size, vs kernel stacks */ /* which are limited to a few K (4 or 8K */ /* typically). */ /***********************************************/ // sp = current->thread.rsp; # if defined(__i386) bos = sp = KSTK_ESP(current); # define ALIGN_MASK 3 # else /***********************************************/ /* KSTK_ESP() doesnt exist for x86_64 (its */ /* set to -1). */ /***********************************************/ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25) # if defined(KSTK_EIP) /***********************************************/ /* Handle ARM and more kernel independent, */ /* but might not exist. */ /***********************************************/ bos = sp = (unsigned long *) KSTK_EIP(current); # else bos = sp = (unsigned long *) task_pt_regs(current)->sp; # endif #else bos = sp = task_pt_regs(current)->rsp; #endif # define ALIGN_MASK 7 #endif /***********************************************/ /* Walk the stack. We cannot rely on a */ /* frame pointer at each level, and we */ /* really want to avoid probing every word */ /* in the stack - a large stack will eat */ /* cpu looking at thousands of entries. So */ /* try and heuristically see if we have a */ /* likely frame pointer to jump over the */ /* frame, but, if not, just go one word at */ /* a time. */ /* */ /* Try and be careful we dont walk outside */ /* the stack or walk backwards in the */ /* stack, too. */ /***********************************************/ { uintptr_t *spend = sp + 1024; struct vm_area_struct *vma = find_vma(current->mm, (unsigned long) sp); if (vma) spend = (uintptr_t *) (vma->vm_end - sizeof(int *)); /*printk("xbos=%p %p\n", bos, spend);*/ /***********************************************/ /* Have you ever looked at the output from */ /* GCC in amd64 mode? Things like: */ /* */ /* push %r12 */ /* push %rbp */ /* */ /* will make you come out in a cold sweat - */ /* no way to find the frame pointer, */ /* without doing what GDB does (ie read the */ /* DWARF stack unwind info). So, for now, */ /* you get some false positives in the */ /* output - but we try to be conservative. */ /***********************************************/ while (sp >= bos && sp < spend && validate_ptr(sp)) { /*printk(" %p %d: %p %d\n", sp, validate_ptr(sp), sp[0], validate_ptr(sp[0]));*/ if (validate_ptr((void *) sp[0])) { uintptr_t p = sp[-1]; /***********************************************/ /* Try and avoid false positives in stack */ /* entries - we want this to be an */ /* executable instruction. */ /***********************************************/ if (((unsigned long *) sp[0] < bos || (unsigned long *) sp[0] > spend) && (vma = find_vma(current->mm, sp[0])) != NULL && vma->vm_flags & VM_EXEC) { *pcstack++ = sp[0]; if (pcstack >= pcstack_end) break; } if (((int) p & ALIGN_MASK) == 0 && p > (uintptr_t) sp && p < (uintptr_t) spend) sp = (unsigned long *) p; } sp++; } } /***********************************************/ /* Erase anything else in the buffer to */ /* avoid confusion. */ /***********************************************/ while (pcstack < pcstack_end) *pcstack++ = (pc_t) NULL; }
static int get_stat(int pid, char * buffer) { struct task_struct ** p = get_task(pid); unsigned long sigignore=0, sigcatch=0, bit=1, wchan; int i,tty_pgrp; char state; if (!p || !*p) return 0; if ((*p)->state < 0 || (*p)->state > 5) state = '.'; else state = "RSDZTD"[(*p)->state]; wchan = get_wchan(*p); for(i=0; i<32; ++i) { switch((int) (*p)->sigaction[i].sa_handler) { case 1: sigignore |= bit; break; case 0: break; default: sigcatch |= bit; } bit <<= 1; } tty_pgrp = (*p)->tty; if (tty_pgrp > 0 && tty_table[tty_pgrp]) tty_pgrp = tty_table[tty_pgrp]->pgrp; else tty_pgrp = -1; return sprintf(buffer,"%d (%s) %c %d %d %d %d %d %u %u \ %u %u %u %d %d %d %d %d %d %u %u %d %u %u %u %u %u %u %u %u %d \ %d %d %d %u\n", pid, (*p)->comm, state, (*p)->p_pptr->pid, (*p)->pgrp, (*p)->session, (*p)->tty, tty_pgrp, (*p)->flags, (*p)->min_flt, (*p)->cmin_flt, (*p)->maj_flt, (*p)->cmaj_flt, (*p)->utime, (*p)->stime, (*p)->cutime, (*p)->cstime, (*p)->counter, /* this is the kernel priority --- subtract 30 in your user-level program. */ (*p)->priority, /* this is the nice value --- subtract 15 in your user-level program. */ (*p)->timeout, (*p)->it_real_value, (*p)->start_time, VSIZE((*p),(*p)->kernel_stack_page), (*p)->rss, /* you might want to shift this left 3 */ (*p)->rlim[RLIMIT_RSS].rlim_cur, (*p)->start_code, (*p)->end_code, (*p)->start_stack, KSTK_ESP((*p)->kernel_stack_page), KSTK_EIP((*p)->kernel_stack_page), (*p)->signal, (*p)->blocked, sigignore, sigcatch, wchan); }
static int get_stat(int pid, char * buffer) { struct task_struct ** p = get_task(pid), *tsk; unsigned long sigignore=0, sigcatch=0, wchan; unsigned long vsize, eip, esp; long priority, nice; int i,tty_pgrp; char state; if (!p || (tsk = *p) == NULL) return 0; if (tsk->state < 0 || tsk->state > 5) state = '.'; else state = "RSDZTW"[tsk->state]; vsize = eip = esp = 0; if (tsk->mm && tsk->mm != &init_mm) { struct vm_area_struct *vma = tsk->mm->mmap; while (vma) { vsize += vma->vm_end - vma->vm_start; vma = vma->vm_next; } if (tsk->kernel_stack_page) { eip = KSTK_EIP(tsk); esp = KSTK_ESP(tsk); } } wchan = get_wchan(tsk); if (tsk->sig) { unsigned long bit = 1; for(i=0; i<32; ++i) { switch((unsigned long) tsk->sig->action[i].sa_handler) { case 0: break; case 1: sigignore |= bit; break; default: sigcatch |= bit; } bit <<= 1; } } if (tsk->tty) tty_pgrp = tsk->tty->pgrp; else tty_pgrp = -1; /* scale priority and nice values from timeslices to -20..20 */ /* to make it look like a "normal" unix priority/nice value */ priority = tsk->counter; priority = 20 - (priority * 10 + DEF_PRIORITY / 2) / DEF_PRIORITY; nice = tsk->priority; nice = 20 - (nice * 20 + DEF_PRIORITY / 2) / DEF_PRIORITY; return sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \ %lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %lu %lu %ld %lu %lu %lu %lu %lu \ %lu %lu %lu %lu %lu %lu %lu %lu\n", pid, tsk->comm, state, tsk->p_pptr->pid, tsk->pgrp, tsk->session, tsk->tty ? kdev_t_to_nr(tsk->tty->device) : 0, tty_pgrp, tsk->flags, tsk->min_flt, tsk->cmin_flt, tsk->maj_flt, tsk->cmaj_flt, tsk->utime, tsk->stime, tsk->cutime, tsk->cstime, priority, nice, tsk->timeout, tsk->it_real_value, tsk->start_time, vsize, tsk->mm ? tsk->mm->rss : 0, /* you might want to shift this left 3 */ tsk->rlim ? tsk->rlim[RLIMIT_RSS].rlim_cur : 0, tsk->mm ? tsk->mm->start_code : 0, tsk->mm ? tsk->mm->end_code : 0, tsk->mm ? tsk->mm->start_stack : 0, esp, eip, tsk->signal, tsk->blocked, sigignore, sigcatch, wchan, tsk->nswap, tsk->cnswap); }