]> sourceware.org Git - systemtap.git/blame - staplog.c
2007-10-19 Masami Hiramatsu <mhiramat@redhat.com>
[systemtap.git] / staplog.c
CommitLineData
35a04c8e
FCE
1/*
2 crash shared object for retrieving systemtap buffer
3 Copyright (c) 2007 Hitachi,Ltd.,
1673e81e 4 Created by Satoru Moriya <satoru.moriya.br@hitachi.com>
35a04c8e
FCE
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19*/
20
21
22/* crash/defs.h defines NR_CPUS based upon architecture macros
23 X86, X86_64, etc. See crash/configure.c (!). */
24#ifdef __alpha__
25#define ALPHA
26#endif
27#ifdef __i386__
28#define X86
29#endif
30#ifdef __powerpc__
31#define PPC
32#endif
33#ifdef __ia64__
34#define IA64
35#endif
36#ifdef __s390__
37#define S390
38#endif
39#ifdef __s390x__
40#define S390X
41#endif
42#ifdef __powerpc64__
43#define PPC64
44#endif
45#ifdef __x86_64__
46#define X86_64
47#endif
48
49#include <crash/defs.h>
50
35a04c8e
FCE
51struct rchan_offsets {
52 long subbuf_size;
53 long n_subbufs;
54 long buf;
55 long buf_start;
56 long buf_offset;
57 long buf_subbufs_produced;
58 long buf_padding;
59};
60
61struct fake_rchan_buf {
62 void *start;
63 size_t offset;
64 size_t subbufs_produced;
65 size_t *padding;
66};
67
68struct fake_rchan {
69 size_t subbuf_size;
70 size_t n_subbufs;
71};
72
73struct per_cpu_data {
74 struct fake_rchan_buf buf;
75};
76
77static struct rchan_offsets rchan_offsets;
78static struct fake_rchan chan;
79static struct per_cpu_data per_cpu[NR_CPUS];
80static FILE *outfp;
81static char *subbuf;
82static int is_global;
1673e81e 83static int is_broken;
35a04c8e 84static int old_format;
1673e81e 85static int retrieve_all;
35a04c8e
FCE
86
87void cmd_staplog(void);
88void cmd_staplog_cleanup(void);
89char *help_staplog[];
90char *help_staplog_cleanup[];
91
92static struct command_table_entry command_table[] = {
93 {"staplog", cmd_staplog, help_staplog, 0},
94 {"staplog_cleanup", cmd_staplog_cleanup, help_staplog_cleanup, CLEANUP},
95 {NULL, NULL, NULL, 0},
96};
97
98static void get_rchan_offsets(void)
99{
100 rchan_offsets.subbuf_size = MEMBER_OFFSET("rchan", "subbuf_size");
101 if (rchan_offsets.subbuf_size < 0)
102 goto ERR;
103 rchan_offsets.n_subbufs = MEMBER_OFFSET("rchan", "n_subbufs");
104 if (rchan_offsets.n_subbufs < 0)
105 goto ERR;
106 rchan_offsets.buf = MEMBER_OFFSET("rchan", "buf");
107 if (rchan_offsets.buf < 0)
108 goto ERR;
109 rchan_offsets.buf_start = MEMBER_OFFSET("rchan_buf", "start");
110 if (rchan_offsets.buf_start < 0)
111 goto ERR;
112 rchan_offsets.buf_offset = MEMBER_OFFSET("rchan_buf", "offset");
113 if (rchan_offsets.buf_offset < 0)
114 goto ERR;
115 rchan_offsets.buf_subbufs_produced
116 = MEMBER_OFFSET("rchan_buf", "subbufs_produced");
117 if (rchan_offsets.buf_subbufs_produced < 0)
118 goto ERR;
119 rchan_offsets.buf_padding = MEMBER_OFFSET("rchan_buf", "padding");
120 if (rchan_offsets.buf_padding < 0)
121 goto ERR;
122 return;
123ERR:
124 error(FATAL, "cannot get rchan offset\n");
125}
126
127static ulong get_rchan(ulong chan_addr)
128{
129 ulong rchan;
130
131 readmem(chan_addr, KVADDR, &rchan, sizeof(void*),
132 "stp_channel", FAULT_ON_ERROR);
133 readmem(rchan + rchan_offsets.subbuf_size,
134 KVADDR, &chan.subbuf_size, sizeof(size_t),
135 "stp_channel.subbuf_size", FAULT_ON_ERROR);
136 readmem(rchan + rchan_offsets.n_subbufs,
137 KVADDR, &chan.n_subbufs, sizeof(size_t),
138 "stp_channel.n_subbufs", FAULT_ON_ERROR);
139 return rchan;
140}
141
142static void get_rchan_buf(int cpu, ulong rchan)
143{
144 ulong rchan_buf;
145 struct per_cpu_data *pcd;
146
147 pcd = &per_cpu[cpu];
148 readmem(rchan + rchan_offsets.buf + sizeof(void*) * cpu,
149 KVADDR, &rchan_buf, sizeof(void*),
150 "stp_channel.buf", FAULT_ON_ERROR);
151 readmem(rchan_buf + rchan_offsets.buf_start,
152 KVADDR, &pcd->buf.start, sizeof(void*),
153 "stp_channel.buf.start", FAULT_ON_ERROR);
154 readmem(rchan_buf + rchan_offsets.buf_offset,
155 KVADDR, &pcd->buf.offset, sizeof(size_t),
156 "stp_channel.buf.offset", FAULT_ON_ERROR);
157 readmem(rchan_buf + rchan_offsets.buf_subbufs_produced,
158 KVADDR, &pcd->buf.subbufs_produced, sizeof(size_t),
159 "stp_channel.buf.subbufs_produced", FAULT_ON_ERROR);
160 readmem(rchan_buf + rchan_offsets.buf_padding,
161 KVADDR, &pcd->buf.padding, sizeof(size_t*),
162 "stp_channel.buf.padding", FAULT_ON_ERROR);
163 return;
164}
165
166static ulong get_rchan_addr(ulong stp_utt_addr)
167{
168 ulong stp_utt;
faf96009 169 long offset;
35a04c8e
FCE
170
171 readmem(stp_utt_addr, KVADDR, &stp_utt, sizeof(void*),
172 "stp_utt", FAULT_ON_ERROR);
faf96009
FCE
173
174 /*
175 * If we couldn't get the member offset of struct utt_trace.rchan,
176 * i.e. the debuginfo of the trace module isn't available, we use
177 * sizeof(long) as the offset instead. Currently struct utt_trace
178 * is defined as below:
179 *
180 * struct utt_trace {
181 * int trace_state;
182 * struct rchan *rchan;
183 * ...
184 * }
185 *
186 * Although the type of the preceding member is int, sizeof(long)
187 * is OK, because rchan is aligned with long size on both 32-bit
188 * and 64-bit environment. When the definision of struct utt_trace
189 * changed, we must check if this code is correct.
190 */
191 if ((offset = MEMBER_OFFSET("utt_trace", "rchan")) < 0) {
192 error(WARNING, "The debuginfo of the trace module hasn't been loaded. "
193 "You may not be able to retrieve the correct trace data.\n");
194 offset = sizeof(long);
195 }
196
197 return (stp_utt + (ulong)offset);
35a04c8e
FCE
198}
199
200static int check_global_buffer(ulong rchan)
201{
202 int cpu;
203 ulong rchan_buf[2];
204
205 for (cpu = 0; cpu < 2; cpu++) {
206 readmem(rchan + rchan_offsets.buf + sizeof(void*) * cpu,
207 KVADDR, &rchan_buf[cpu], sizeof(void*),
208 "stp_channel.buf", FAULT_ON_ERROR);
209 }
210 if (rchan_buf[0] == rchan_buf[1])
211 return 1;
212 return 0;
213}
214
215static void setup_global_data(char *module)
216{
217 int i;
218 ulong stp_utt_addr = 0;
219 ulong stp_rchan_addr = 0;
220 ulong rchan;
221
222 stp_utt_addr = symbol_value_module("_stp_utt", module);
223 if (stp_utt_addr == 0) {
224 stp_rchan_addr = symbol_value_module("_stp_chan", module);
225 if (stp_rchan_addr == 0) {
226 error(FATAL, "Failed to find _stp_utt/_stp_chan.\n",
227 module);
228 }
229 old_format = 1;
230 } else {
231 stp_rchan_addr = get_rchan_addr(stp_utt_addr);
232 if (stp_rchan_addr == 0) {
233 error(FATAL, "Failed to find _stp_utt/_stp_chan.\n",
234 module);
235 }
236 }
237 rchan = get_rchan(stp_rchan_addr);
238 for (i = 0; i < kt->cpus; i++)
239 get_rchan_buf(i, rchan);
240
241 if (kt->cpus > 1) {
242 is_global = check_global_buffer(rchan);
243 }
244 return;
245}
246
1673e81e
MH
247static char *create_output_filename(int cpu)
248{
249 size_t max = 128;
250 char *fname;
251
252 fname = (char *)malloc(sizeof(char) * max);
253 if (is_global) {
254 sprintf(fname, "global");
255 } else {
256 sprintf(fname, "cpu%d", cpu);
257 }
258 if (is_broken) {
259 strcat(fname, ".may_broken");
260 }
261 return fname;
262}
263
264static void print_rchan_info(size_t start, size_t end, size_t ready,
265 size_t offset, char *dname, char *fname, int cpu)
266{
267 size_t start_subbuf, end_subbuf;
268
269 start_subbuf = start ? start - chan.n_subbufs : start;
270 end_subbuf = start ? end - 1 - chan.n_subbufs : end - 1;
271
272 fprintf(fp, "--- generating '%s/%s' ---\n", dname, fname);
273 if (is_broken) {
274 fprintf(fp, " read subbuf %ld(%ld) (offset:%ld-%ld)\n",
275 (long)end_subbuf - chan.n_subbufs,
276 (long)(end_subbuf % chan.n_subbufs),
277 (long)offset,
278 (long)chan.subbuf_size);
279 } else {
280 fprintf(fp, " subbufs ready on relayfs:%ld\n", (long)ready);
281 fprintf(fp, " n_subbufs:%ld, read subbuf from:%ld(%ld) "
282 "to:%ld(%ld) (offset:0-%ld)\n\n",
283 (long)chan.n_subbufs,
284 (long)start_subbuf,
285 (long)(start_subbuf % chan.n_subbufs),
286 (long)end_subbuf,
287 (long)(end_subbuf % chan.n_subbufs),
288 (long)offset);
289 }
290}
291
292static void create_output_dir(char *dirname)
293{
294 DIR *dir;
295 dir = opendir(dirname);
296 if (dir) {
297 closedir(dir);
298 } else {
299 if (mkdir(dirname, S_IRWXU) < 0) {
300 error(FATAL, "cannot create log directory '%s\n'", dirname);
301 }
302 }
303}
304
305static FILE *open_output_file(char *dname, char *fname)
306{
307 FILE *filp = NULL;
308 char *output_file;
309 size_t dlength, flength;
310
311 dlength = strlen(dname);
312 flength = strlen(fname);
313
314 output_file = (char *)malloc(sizeof(char) * (dlength + flength) + 1);
315 output_file[dlength + flength] = '\0';
316
317 create_output_dir(dname);
318 sprintf(output_file,"%s/%s", dname, fname);
319
320 filp = fopen(output_file, "w");
321 if (!filp) {
322 error(FATAL, "cannot create log file '%s'\n", output_file);
323 }
324
325 return filp;
326}
327
faf96009 328static void output_cpu_logs(char *dirname)
35a04c8e 329{
1673e81e 330 int i;
35a04c8e 331 struct per_cpu_data *pcd;
1673e81e 332 size_t n, idx, start, end, len;
faf96009 333 size_t padding;
1673e81e 334 char *source, *fname;
35a04c8e 335
35a04c8e
FCE
336 /* allocate subbuf memory */
337 subbuf = GETBUF(chan.subbuf_size);
338 if (!subbuf) {
339 error(FATAL, "cannot allocate memory\n");
340 }
341
35a04c8e 342 for (i = 0; i < kt->cpus; i++) {
1673e81e 343 is_broken = 0;
35a04c8e
FCE
344 pcd = &per_cpu[i];
345
1673e81e 346 if (pcd->buf.subbufs_produced == 0 && pcd->buf.offset == 0) {
faf96009
FCE
347 if (is_global == 1) {
348 error(WARNING, "There is no data in the relay buffer.\n");
349 break;
350 } else {
351 error(WARNING, "[cpu:%d]There is no data in the relay buffer.\n", i);
352 continue;
353 }
354 }
35a04c8e 355
1673e81e
MH
356 if (pcd->buf.subbufs_produced >= chan.n_subbufs) {
357 start = pcd->buf.subbufs_produced + 1;
35a04c8e
FCE
358 end = start + chan.n_subbufs;
359 } else {
360 start = 0;
1673e81e 361 end = pcd->buf.subbufs_produced + 1;
35a04c8e 362 }
1673e81e
MH
363
364 fname = create_output_filename(i);
365 print_rchan_info(start, end, pcd->buf.subbufs_produced + 1,
366 pcd->buf.offset, dirname, fname, i);
367 outfp = open_output_file(dirname, fname);
368
35a04c8e
FCE
369 for (n = start; n < end; n++) {
370 /* read relayfs subbufs and write to log file */
371 idx = n % chan.n_subbufs;
372 source = pcd->buf.start + idx * chan.subbuf_size;
373 readmem((ulong)pcd->buf.padding + sizeof(padding) * idx,
374 KVADDR, &padding, sizeof(padding),
375 "padding", FAULT_ON_ERROR);
1673e81e 376 if (n == end - 1 &&
35a04c8e
FCE
377 pcd->buf.offset < chan.subbuf_size) {
378 len = pcd->buf.offset;
379 } else {
380 len = chan.subbuf_size;
381 }
382 if (old_format == 1) {
1673e81e
MH
383 source += sizeof(unsigned int);
384 len -= sizeof(unsigned int) + padding;
35a04c8e
FCE
385 } else {
386 len -= padding;
387 }
388 if (len) {
389 readmem((ulong)source, KVADDR, subbuf, len,
390 "subbuf", FAULT_ON_ERROR);
391 if (fwrite(subbuf, len, 1, outfp) != 1) {
392 error(FATAL, "cannot write log data\n");
393 }
394 }
395 }
396 fclose(outfp);
397 outfp = NULL;
1673e81e
MH
398 free(fname);
399 fname = NULL;
400
401 /*
402 * -a option retrieve the old data of subbuffer where the
403 * probe record is written at that time.
404 */
405 if (retrieve_all == 1 &&
406 pcd->buf.subbufs_produced >= chan.n_subbufs) {
407 is_broken = 1;
408 fname = create_output_filename(i);
409 print_rchan_info(start, end,
410 pcd->buf.subbufs_produced + 1,
411 pcd->buf.offset, dirname, fname, i);
412 outfp = open_output_file(dirname, fname);
413 idx = (end - 1) % chan.n_subbufs;
414 source = pcd->buf.start + idx * chan.subbuf_size +
415 pcd->buf.offset;
416 readmem((ulong)pcd->buf.padding + sizeof(padding)*idx,
417 KVADDR, &padding, sizeof(padding),
418 "padding", FAULT_ON_ERROR);
419 len = chan.subbuf_size - pcd->buf.offset;
420 if (len) {
421 readmem((ulong)source, KVADDR, subbuf, len,
422 "may_broken_subbuf", FAULT_ON_ERROR);
423 if(fwrite(subbuf, len, 1, outfp) != 1) {
424 error(FATAL,
425 "cannot write log data(may_broken)\n");
426 }
427 }
428 fclose(outfp);
429 outfp = NULL;
430 free(fname);
431 fname = NULL;
432 }
35a04c8e
FCE
433 if (is_global == 1)
434 break;
435 }
436 if (subbuf) {
437 FREEBUF(subbuf);
438 subbuf = NULL;
439 }
440 return;
441}
442
faf96009 443static void do_staplog(char *module, char *dirname)
35a04c8e
FCE
444{
445 setup_global_data(module);
faf96009 446 output_cpu_logs(dirname);
35a04c8e
FCE
447 return;
448}
449
450void cmd_staplog(void)
451{
452
453 int c;
454 char *module = NULL;
faf96009 455 char *dirname = NULL;
35a04c8e 456
1673e81e 457 while ((c = getopt(argcnt, args, "+ao:")) != EOF) {
35a04c8e 458 switch (c) {
1673e81e
MH
459 case 'a':
460 retrieve_all = 1;
461 break;
35a04c8e 462 case 'o':
faf96009 463 dirname = optarg;
35a04c8e
FCE
464 break;
465 default:
466 argerrs++;
467 break;
468 }
469 }
470 module = args[optind];
471
472 if (!module || argerrs)
473 cmd_usage(pc->curcmd, SYNOPSIS);
474
faf96009
FCE
475 if (dirname == NULL && module != NULL)
476 dirname = module;
477 do_staplog(module, dirname);
35a04c8e
FCE
478 return;
479}
480
481void cmd_staplog_cleanup(void)
482{
483 if (outfp) {
484 fclose(outfp);
485 outfp = NULL;
486 }
487 return;
488}
489
490char *help_staplog[] = {
491 "systemtaplog",
492 "Retrieve SystemTap log data",
1673e81e 493 "[-a] [-o dir_name] module_name",
35a04c8e 494 " Retrieve SystemTap's log data and write them to files.\n",
1673e81e
MH
495 " All valid SystemTap's log data made by the trace module which name",
496 " is 'module_name' are written into log files. This command starts",
497 " to retrieve log data from the subbuffer which is next to current",
498 " written subbuffer. Therefore some old data in the current written",
499 " subbuffer may not be retrieved. But -a option retrieve these data",
500 " and write them into another log file which have the special ",
501 " postfix `.may_broken`.",
502 " If you don't use -o option, the log files are created in",
503 " `module_name` directory. The name of each log file is cpu0, cpu1..",
504 " ...cpuN. This command don't change the log data format, but remove",
505 " only padding.",
35a04c8e 506 "",
1673e81e
MH
507 " -a Retrieve the old data which is recorded in",
508 " current written subbufer and create another file",
509 " that have the special postfix `.may_broken`",
510 " for these data.",
35a04c8e
FCE
511 " -o file_name Specify the output directory.",
512 NULL,
513};
514
515char *help_staplog_cleanup[] = {
516 "systemtaplog cleanup (hidden)",
517 "Cleanup command for staplog",
518 "",
519 " This command is called during restore_sanity() prior to each ",
520 " command prompt to close the files which was opened and failed to",
521 " close by staplog command.",
522 NULL,
523};
524
525static void __attribute__ ((constructor)) _init(void)
526{
527 get_rchan_offsets();
528 register_extension(command_table);
529 return;
530}
531
532
533static void __attribute__ ((destructor)) _fini(void)
534{
535 return;
536}
This page took 0.072965 seconds and 5 git commands to generate.