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