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