]> git.proxmox.com Git - mirror_spl-debian.git/blob - cmd/spl.c
a77ad9ca469ca4b386b0149e317098405b5820e7
[mirror_spl-debian.git] / cmd / spl.c
1 /*****************************************************************************\
2 * Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
3 * Copyright (C) 2007 The Regents of the University of California.
4 * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
5 * Written by Brian Behlendorf <behlendorf1@llnl.gov>.
6 * UCRL-CODE-235197
7 *
8 * This file is part of the SPL, Solaris Porting Layer.
9 * For details, see <http://github.com/behlendorf/spl/>.
10 *
11 * The SPL is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by the
13 * Free Software Foundation; either version 2 of the License, or (at your
14 * option) any later version.
15 *
16 * The SPL is distributed in the hope that it will be useful, but WITHOUT
17 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19 * for more details.
20 *
21 * You should have received a copy of the GNU General Public License along
22 * with the SPL. If not, see <http://www.gnu.org/licenses/>.
23 *****************************************************************************
24 * Solaris Porting Layer (SPL) User Space Interface.
25 \*****************************************************************************/
26
27 #include <stdlib.h>
28 #include <stddef.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <errno.h>
32 #include <unistd.h>
33 #include <sys/types.h>
34 #include <fcntl.h>
35 #include "../include/spl-ctl.h"
36
37 static int spl_debug_mask = ~0;
38 static int spl_debug_subsystem = ~0;
39
40 /* all strings nul-terminated; only the struct and hdr need to be freed */
41 struct dbg_line {
42 struct spl_debug_header *hdr;
43 char *file;
44 char *fn;
45 char *text;
46 };
47
48 static int
49 cmp_rec(const void *p1, const void *p2)
50 {
51 struct dbg_line *d1 = *(struct dbg_line **)p1;
52 struct dbg_line *d2 = *(struct dbg_line **)p2;
53
54 if (d1->hdr->ph_sec < d2->hdr->ph_sec)
55 return -1;
56
57 if (d1->hdr->ph_sec == d2->hdr->ph_sec &&
58 d1->hdr->ph_usec < d2->hdr->ph_usec)
59 return -1;
60
61 if (d1->hdr->ph_sec == d2->hdr->ph_sec &&
62 d1->hdr->ph_usec == d2->hdr->ph_usec)
63 return 0;
64
65 return 1;
66 }
67
68 static void
69 print_rec(struct dbg_line **linev, int used, FILE *out)
70 {
71 int i;
72
73 for (i = 0; i < used; i++) {
74 struct dbg_line *line = linev[i];
75 struct spl_debug_header *hdr = line->hdr;
76
77 fprintf(out, "%08x:%08x:%u:%u.%06llu:%u:%u:%u:(%s:%u:%s()) %s",
78 hdr->ph_subsys, hdr->ph_mask, hdr->ph_cpu_id,
79 hdr->ph_sec, (unsigned long long)hdr->ph_usec,
80 hdr->ph_stack, hdr->ph_pid, hdr->ph_stack, line->file,
81 hdr->ph_line_num, line->fn, line->text);
82 free(line->hdr);
83 free(line);
84 }
85
86 free(linev);
87 }
88
89 static int
90 add_rec(struct dbg_line *line, struct dbg_line ***linevp, int *lenp, int used)
91 {
92 struct dbg_line **linev = *linevp;
93
94 if (used == *lenp) {
95 int nlen = *lenp + 512;
96 int nsize = nlen * sizeof(struct dbg_line *);
97
98 linev = *linevp ? realloc(*linevp, nsize) : malloc(nsize);
99 if (!linev)
100 return 0;
101 *linevp = linev;
102 *lenp = nlen;
103 }
104 linev[used] = line;
105 return 1;
106 }
107
108 static int
109 parse_buffer(FILE *in, FILE *out)
110 {
111 struct dbg_line *line;
112 struct spl_debug_header *hdr;
113 char buf[4097], *p;
114 unsigned long dropped = 0, kept = 0;
115 struct dbg_line **linev = NULL;
116 const int phl = sizeof(hdr->ph_len);
117 const int phf = sizeof(hdr->ph_flags);
118 int rc, linev_len = 0;
119
120 while (1) {
121 rc = fread(buf, phl + phf, 1, in);
122 if (rc <= 0)
123 break;
124
125 hdr = (void *)buf;
126 if (hdr->ph_len == 0)
127 break;
128 if (hdr->ph_len > 4094) {
129 fprintf(stderr, "unexpected large record: %d bytes. "
130 "aborting.\n", hdr->ph_len);
131 break;
132 }
133
134 rc = fread(buf + phl + phf, 1, hdr->ph_len - phl - phf, in);
135 if (rc <= 0)
136 break;
137
138 if (hdr->ph_mask &&
139 (!(spl_debug_subsystem & hdr->ph_subsys) ||
140 (!(spl_debug_mask & hdr->ph_mask)))) {
141 dropped++;
142 continue;
143 }
144
145 line = malloc(sizeof(*line));
146 if (line == NULL) {
147 fprintf(stderr, "malloc failed; printing accumulated "
148 "records and exiting.\n");
149 break;
150 }
151
152 line->hdr = malloc(hdr->ph_len + 1);
153 if (line->hdr == NULL) {
154 free(line);
155 fprintf(stderr, "malloc failed; printing accumulated "
156 "records and exiting.\n");
157 break;
158 }
159
160 p = (void *)line->hdr;
161 memcpy(line->hdr, buf, hdr->ph_len);
162 p[hdr->ph_len] = '\0';
163
164 p += sizeof(*hdr);
165 line->file = p;
166 p += strlen(line->file) + 1;
167 line->fn = p;
168 p += strlen(line->fn) + 1;
169 line->text = p;
170
171 if (!add_rec(line, &linev, &linev_len, kept)) {
172 fprintf(stderr, "malloc failed; printing accumulated "
173 "records and exiting.\n");
174 break;
175 }
176 kept++;
177 }
178
179 if (linev) {
180 qsort(linev, kept, sizeof(struct dbg_line *), cmp_rec);
181 print_rec(linev, kept, out);
182 }
183
184 printf("Debug log: %lu lines, %lu kept, %lu dropped.\n",
185 dropped + kept, kept, dropped);
186 return 0;
187 }
188
189 int
190 main(int argc, char *argv[])
191 {
192 int fdin, fdout;
193 FILE *in, *out = stdout;
194 int rc, o_lf = 0;
195
196 if (argc > 3 || argc < 2) {
197 fprintf(stderr, "usage: %s <input> [output]\n", argv[0]);
198 return 0;
199 }
200
201 #ifdef __USE_LARGEFILE64
202 o_lf = O_LARGEFILE;
203 #endif
204
205 fdin = open(argv[1], O_RDONLY | o_lf);
206 if (fdin == -1) {
207 fprintf(stderr, "open(%s) failed: %s\n", argv[1],
208 strerror(errno));
209 return 1;
210 }
211 in = fdopen(fdin, "r");
212 if (in == NULL) {
213 fprintf(stderr, "fopen(%s) failed: %s\n", argv[1],
214 strerror(errno));
215 close(fdin);
216 return 1;
217 }
218 if (argc > 2) {
219 fdout = open(argv[2], O_CREAT | O_TRUNC | O_WRONLY | o_lf, 0600);
220 if (fdout == -1) {
221 fprintf(stderr, "open(%s) failed: %s\n", argv[2],
222 strerror(errno));
223 fclose(in);
224 return 1;
225 }
226 out = fdopen(fdout, "w");
227 if (out == NULL) {
228 fprintf(stderr, "fopen(%s) failed: %s\n", argv[2],
229 strerror(errno));
230 fclose(in);
231 close(fdout);
232 return 1;
233 }
234 }
235
236 rc = parse_buffer(in, out);
237
238 fclose(in);
239 if (out != stdout)
240 fclose(out);
241
242 return rc;
243 }