1174199Srwatson/*- 2174199Srwatson * Copyright (c) 2007 Robert N. M. Watson 3174199Srwatson * All rights reserved. 4174199Srwatson * 5174199Srwatson * Redistribution and use in source and binary forms, with or without 6174199Srwatson * modification, are permitted provided that the following conditions 7174199Srwatson * are met: 8174199Srwatson * 1. Redistributions of source code must retain the above copyright 9174199Srwatson * notice, this list of conditions and the following disclaimer. 10174199Srwatson * 2. Redistributions in binary form must reproduce the above copyright 11174199Srwatson * notice, this list of conditions and the following disclaimer in the 12174199Srwatson * documentation and/or other materials provided with the distribution. 13174199Srwatson * 14174199Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15174199Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16174199Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17174199Srwatson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18174199Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19174199Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20174199Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21174199Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22174199Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23174199Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24174199Srwatson * SUCH DAMAGE. 25174199Srwatson * 26174199Srwatson * $FreeBSD: stable/10/usr.bin/procstat/procstat_kstack.c 310121 2016-12-15 16:52:17Z vangyzen $ 27174199Srwatson */ 28174199Srwatson 29186567Srwatson#include <sys/param.h> 30174199Srwatson#include <sys/sysctl.h> 31174199Srwatson#include <sys/user.h> 32174199Srwatson 33174199Srwatson#include <err.h> 34174199Srwatson#include <errno.h> 35221807Sstas#include <libprocstat.h> 36174199Srwatson#include <stdio.h> 37174199Srwatson#include <stdlib.h> 38174199Srwatson#include <string.h> 39174199Srwatson 40174199Srwatson#include "procstat.h" 41174199Srwatson 42174199Srwatson/* 43174199Srwatson * Walk the stack trace provided by the kernel and reduce it to what we 44174199Srwatson * actually want to print. This involves stripping true instruction pointers, 45174199Srwatson * frame numbers, and carriage returns as generated by stack(9). If -kk is 46174199Srwatson * specified, print the function and offset, otherwise just the function. 47174199Srwatson */ 48174199Srwatsonenum trace_state { TS_FRAMENUM, TS_PC, TS_AT, TS_FUNC, TS_OFF }; 49174199Srwatson 50174199Srwatsonstatic enum trace_state 51174199Srwatsonkstack_nextstate(enum trace_state ts) 52174199Srwatson{ 53174199Srwatson 54174199Srwatson switch (ts) { 55174199Srwatson case TS_FRAMENUM: 56174199Srwatson return (TS_PC); 57174199Srwatson 58174199Srwatson case TS_PC: 59174199Srwatson return (TS_AT); 60174199Srwatson 61174199Srwatson case TS_AT: 62174199Srwatson return (TS_FUNC); 63174199Srwatson 64174199Srwatson case TS_FUNC: 65174199Srwatson return (TS_OFF); 66174199Srwatson 67174199Srwatson case TS_OFF: 68174199Srwatson return TS_FRAMENUM; 69174199Srwatson 70174199Srwatson default: 71174199Srwatson errx(-1, "kstack_nextstate"); 72174199Srwatson } 73174199Srwatson} 74174199Srwatson 75174199Srwatsonstatic void 76174199Srwatsonkstack_cleanup(const char *old, char *new, int kflag) 77174199Srwatson{ 78174199Srwatson enum trace_state old_ts, ts; 79174199Srwatson const char *cp_old; 80174199Srwatson char *cp_new; 81174199Srwatson 82174199Srwatson ts = TS_FRAMENUM; 83174199Srwatson for (cp_old = old, cp_new = new; *cp_old != '\0'; cp_old++) { 84174199Srwatson switch (*cp_old) { 85174199Srwatson case ' ': 86174199Srwatson case '\n': 87174199Srwatson case '+': 88174199Srwatson old_ts = ts; 89174199Srwatson ts = kstack_nextstate(old_ts); 90174199Srwatson if (old_ts == TS_OFF) { 91174199Srwatson *cp_new = ' '; 92174199Srwatson cp_new++; 93174199Srwatson } 94174199Srwatson if (kflag > 1 && old_ts == TS_FUNC) { 95174199Srwatson *cp_new = '+'; 96174199Srwatson cp_new++; 97174199Srwatson } 98174199Srwatson continue; 99174199Srwatson } 100174199Srwatson if (ts == TS_FUNC || (kflag > 1 && ts == TS_OFF)) { 101174199Srwatson *cp_new = *cp_old; 102174199Srwatson cp_new++; 103174199Srwatson } 104174199Srwatson } 105174199Srwatson *cp_new = '\0'; 106174199Srwatson} 107174199Srwatson 108174199Srwatson/* 109174199Srwatson * Sort threads by tid. 110174199Srwatson */ 111174199Srwatsonstatic int 112174199Srwatsonkinfo_kstack_compare(const void *a, const void *b) 113174199Srwatson{ 114174199Srwatson 115176107Sdwmalone return ((const struct kinfo_kstack *)a)->kkst_tid - 116176107Sdwmalone ((const struct kinfo_kstack *)b)->kkst_tid; 117174199Srwatson} 118174199Srwatson 119174199Srwatsonstatic void 120174199Srwatsonkinfo_kstack_sort(struct kinfo_kstack *kkstp, int count) 121174199Srwatson{ 122174199Srwatson 123174199Srwatson qsort(kkstp, count, sizeof(*kkstp), kinfo_kstack_compare); 124174199Srwatson} 125174199Srwatson 126174199Srwatson 127174199Srwatsonvoid 128249685Strocinyprocstat_kstack(struct procstat *procstat, struct kinfo_proc *kipp, int kflag) 129174199Srwatson{ 130174199Srwatson struct kinfo_kstack *kkstp, *kkstp_free; 131174230Srwatson struct kinfo_proc *kip, *kip_free; 132174199Srwatson char trace[KKST_MAXLEN]; 133176107Sdwmalone unsigned int i, j; 134249685Strociny unsigned int kip_count, kstk_count; 135174199Srwatson 136174199Srwatson if (!hflag) 137310121Svangyzen printf("%5s %6s %-19s %-19s %-29s\n", "PID", "TID", "COMM", 138174230Srwatson "TDNAME", "KSTACK"); 139174199Srwatson 140249685Strociny kkstp = kkstp_free = procstat_getkstack(procstat, kipp, &kstk_count); 141174199Srwatson if (kkstp == NULL) 142174199Srwatson return; 143174199Srwatson 144174230Srwatson /* 145174230Srwatson * We need to re-query for thread information, so don't use *kipp. 146174230Srwatson */ 147249685Strociny kip = kip_free = procstat_getprocs(procstat, 148249685Strociny KERN_PROC_PID | KERN_PROC_INC_THREAD, kipp->ki_pid, &kip_count); 149174230Srwatson 150249685Strociny if (kip == NULL) { 151249685Strociny procstat_freekstack(procstat, kkstp_free); 152174230Srwatson return; 153174230Srwatson } 154174230Srwatson 155249685Strociny kinfo_kstack_sort(kkstp, kstk_count); 156249685Strociny for (i = 0; i < kstk_count; i++) { 157174199Srwatson kkstp = &kkstp_free[i]; 158174230Srwatson 159174230Srwatson /* 160174230Srwatson * Look up the specific thread using its tid so we can 161174230Srwatson * display the per-thread command line. 162174230Srwatson */ 163174230Srwatson kipp = NULL; 164249685Strociny for (j = 0; j < kip_count; j++) { 165174230Srwatson kipp = &kip_free[j]; 166174230Srwatson if (kkstp->kkst_tid == kipp->ki_tid) 167174230Srwatson break; 168174230Srwatson } 169174230Srwatson if (kipp == NULL) 170174230Srwatson continue; 171174230Srwatson 172221807Sstas printf("%5d ", kipp->ki_pid); 173174199Srwatson printf("%6d ", kkstp->kkst_tid); 174310121Svangyzen printf("%-19s ", kipp->ki_comm); 175310121Svangyzen printf("%-19s ", kinfo_proc_thread_name(kipp)); 176174199Srwatson 177174199Srwatson switch (kkstp->kkst_state) { 178174199Srwatson case KKST_STATE_RUNNING: 179174230Srwatson printf("%-29s\n", "<running>"); 180174199Srwatson continue; 181174199Srwatson 182174199Srwatson case KKST_STATE_SWAPPED: 183174230Srwatson printf("%-29s\n", "<swapped>"); 184174199Srwatson continue; 185174199Srwatson 186174199Srwatson case KKST_STATE_STACKOK: 187174199Srwatson break; 188174199Srwatson 189174199Srwatson default: 190174230Srwatson printf("%-29s\n", "<unknown>"); 191174199Srwatson continue; 192174199Srwatson } 193174199Srwatson 194174199Srwatson /* 195174199Srwatson * The kernel generates a trace with carriage returns between 196174199Srwatson * entries, but for a more compact view, we convert carriage 197174199Srwatson * returns to spaces. 198174199Srwatson */ 199174199Srwatson kstack_cleanup(kkstp->kkst_trace, trace, kflag); 200174230Srwatson printf("%-29s\n", trace); 201174199Srwatson } 202249685Strociny procstat_freekstack(procstat, kkstp_free); 203249685Strociny procstat_freeprocs(procstat, kip_free); 204174199Srwatson} 205