]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - usr.bin/procstat/procstat_kstack.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / usr.bin / procstat / procstat_kstack.c
1 /*-
2  * Copyright (c) 2007 Robert N. M. Watson
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD$
27  */
28
29 #include <sys/param.h>
30 #include <sys/sysctl.h>
31 #include <sys/user.h>
32
33 #include <err.h>
34 #include <errno.h>
35 #include <libprocstat.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39
40 #include "procstat.h"
41
42 /*
43  * Walk the stack trace provided by the kernel and reduce it to what we
44  * actually want to print.  This involves stripping true instruction pointers,
45  * frame numbers, and carriage returns as generated by stack(9).  If -kk is
46  * specified, print the function and offset, otherwise just the function.
47  */
48 enum trace_state { TS_FRAMENUM, TS_PC, TS_AT, TS_FUNC, TS_OFF };
49
50 static enum trace_state
51 kstack_nextstate(enum trace_state ts)
52 {
53
54         switch (ts) {
55         case TS_FRAMENUM:
56                 return (TS_PC);
57
58         case TS_PC:
59                 return (TS_AT);
60
61         case TS_AT:
62                 return (TS_FUNC);
63
64         case TS_FUNC:
65                 return (TS_OFF);
66
67         case TS_OFF:
68                 return TS_FRAMENUM;
69
70         default:
71                 errx(-1, "kstack_nextstate");
72         }
73 }
74
75 static void
76 kstack_cleanup(const char *old, char *new, int kflag)
77 {
78         enum trace_state old_ts, ts;
79         const char *cp_old;
80         char *cp_new;
81
82         ts = TS_FRAMENUM;
83         for (cp_old = old, cp_new = new; *cp_old != '\0'; cp_old++) {
84                 switch (*cp_old) {
85                 case ' ':
86                 case '\n':
87                 case '+':
88                         old_ts = ts;
89                         ts = kstack_nextstate(old_ts);
90                         if (old_ts == TS_OFF) {
91                                 *cp_new = ' ';
92                                 cp_new++;
93                         }
94                         if (kflag > 1 && old_ts == TS_FUNC) {
95                                 *cp_new = '+';
96                                 cp_new++;
97                         }
98                         continue;
99                 }
100                 if (ts == TS_FUNC || (kflag > 1 && ts == TS_OFF)) {
101                         *cp_new = *cp_old;
102                         cp_new++;
103                 }
104         }
105         *cp_new = '\0';
106 }
107
108 /*
109  * Sort threads by tid.
110  */
111 static int
112 kinfo_kstack_compare(const void *a, const void *b)
113 {
114
115         return ((const struct kinfo_kstack *)a)->kkst_tid -
116             ((const struct kinfo_kstack *)b)->kkst_tid;
117 }
118
119 static void
120 kinfo_kstack_sort(struct kinfo_kstack *kkstp, int count)
121 {
122
123         qsort(kkstp, count, sizeof(*kkstp), kinfo_kstack_compare);
124 }
125
126
127 void
128 procstat_kstack(struct procstat *procstat, struct kinfo_proc *kipp, int kflag)
129 {
130         struct kinfo_kstack *kkstp, *kkstp_free;
131         struct kinfo_proc *kip, *kip_free;
132         char trace[KKST_MAXLEN];
133         unsigned int i, j;
134         unsigned int kip_count, kstk_count;
135
136         if (!hflag)
137                 printf("%5s %6s %-16s %-16s %-29s\n", "PID", "TID", "COMM",
138                     "TDNAME", "KSTACK");
139
140         kkstp = kkstp_free = procstat_getkstack(procstat, kipp, &kstk_count);
141         if (kkstp == NULL)
142                 return;
143
144         /*
145          * We need to re-query for thread information, so don't use *kipp.
146          */
147         kip = kip_free = procstat_getprocs(procstat,
148             KERN_PROC_PID | KERN_PROC_INC_THREAD, kipp->ki_pid, &kip_count);
149
150         if (kip == NULL) {
151                 procstat_freekstack(procstat, kkstp_free);
152                 return;
153         }
154
155         kinfo_kstack_sort(kkstp, kstk_count);
156         for (i = 0; i < kstk_count; i++) {
157                 kkstp = &kkstp_free[i];
158
159                 /*
160                  * Look up the specific thread using its tid so we can
161                  * display the per-thread command line.
162                  */
163                 kipp = NULL;
164                 for (j = 0; j < kip_count; j++) {
165                         kipp = &kip_free[j];
166                         if (kkstp->kkst_tid == kipp->ki_tid)
167                                 break;
168                 }
169                 if (kipp == NULL)
170                         continue;
171
172                 printf("%5d ", kipp->ki_pid);
173                 printf("%6d ", kkstp->kkst_tid);
174                 printf("%-16s ", kipp->ki_comm);
175                 printf("%-16s ", (strlen(kipp->ki_tdname) &&
176                     (strcmp(kipp->ki_comm, kipp->ki_tdname) != 0)) ?
177                     kipp->ki_tdname : "-");
178
179                 switch (kkstp->kkst_state) {
180                 case KKST_STATE_RUNNING:
181                         printf("%-29s\n", "<running>");
182                         continue;
183
184                 case KKST_STATE_SWAPPED:
185                         printf("%-29s\n", "<swapped>");
186                         continue;
187
188                 case KKST_STATE_STACKOK:
189                         break;
190
191                 default:
192                         printf("%-29s\n", "<unknown>");
193                         continue;
194                 }
195
196                 /*
197                  * The kernel generates a trace with carriage returns between
198                  * entries, but for a more compact view, we convert carriage
199                  * returns to spaces.
200                  */
201                 kstack_cleanup(kkstp->kkst_trace, trace, kflag);
202                 printf("%-29s\n", trace);
203         }
204         procstat_freekstack(procstat, kkstp_free);
205         procstat_freeprocs(procstat, kip_free);
206 }