2 crash shared object for retrieving systemtap buffer
3 Copyright (c) 2007, Hitachi, Ltd.,
4 Copyright (C) 2009-2011, Red Hat Inc.
5 Created by Satoru Moriya <satoru.moriya.br@hitachi.com>
6 Updated by Masami Hiramatsu <mhiramat@redhat.com>
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.
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.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 /* crash/defs.h defines NR_CPUS based upon architecture macros
24 X86, X86_64, etc. See crash/configure.c (!). */
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)
29 #if defined(__alpha__)
31 #elif defined(__x86_64__)
33 #elif defined(__i386__)
35 #elif defined(__powerpc64__)
37 #elif defined(__powerpc__)
39 #elif defined(__ia64__)
41 #elif defined(__s390x__)
43 #elif defined(__s390__)
45 #elif defined(__aarch64__)
47 #elif defined(__arm__)
50 #warn "unknown architecture for crash/staplog support"
55 #include <crash/defs.h>
57 struct rchan_offsets
{
63 long buf_subbufs_produced
;
67 struct fake_rchan_buf
{
70 size_t subbufs_produced
;
80 struct fake_rchan_buf buf
;
83 static struct rchan_offsets rchan_offsets
;
84 static struct fake_rchan chan
;
85 static struct per_cpu_data per_cpu
[NR_CPUS
];
86 static FILE *outfp
= NULL
;
87 static char *subbuf
= NULL
;
88 static int is_global
= 0;
89 static int old_format
= 0;
90 static int retrieve_all
= 0;
92 void cmd_staplog(void);
93 void cmd_staplog_cleanup(void);
95 char *help_staplog_cleanup
[];
97 static 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},
103 static void get_rchan_offsets(void)
105 rchan_offsets
.subbuf_size
= MEMBER_OFFSET("rchan", "subbuf_size");
106 if (rchan_offsets
.subbuf_size
< 0)
108 rchan_offsets
.n_subbufs
= MEMBER_OFFSET("rchan", "n_subbufs");
109 if (rchan_offsets
.n_subbufs
< 0)
111 rchan_offsets
.buf
= MEMBER_OFFSET("rchan", "buf");
112 if (rchan_offsets
.buf
< 0)
114 rchan_offsets
.buf_start
= MEMBER_OFFSET("rchan_buf", "start");
115 if (rchan_offsets
.buf_start
< 0)
117 rchan_offsets
.buf_offset
= MEMBER_OFFSET("rchan_buf", "offset");
118 if (rchan_offsets
.buf_offset
< 0)
120 rchan_offsets
.buf_subbufs_produced
121 = MEMBER_OFFSET("rchan_buf", "subbufs_produced");
122 if (rchan_offsets
.buf_subbufs_produced
< 0)
124 rchan_offsets
.buf_padding
= MEMBER_OFFSET("rchan_buf", "padding");
125 if (rchan_offsets
.buf_padding
< 0)
129 error(FATAL
, "cannot get rchan offset\n");
133 * Here's a description of 'readmem()' from crash:
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:
140 * addr a user, kernel or physical memory address.
141 * memtype addr type: UVADDR, KVADDR, PHYSADDR, XENMACHADDR or
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
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.
153 static ulong
get_rchan(ulong rchan_addr
)
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
);
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
);
178 static void get_rchan_buf(int cpu
, ulong rchan
)
181 struct per_cpu_data
*pcd
;
184 readmem(rchan
+ rchan_offsets
.buf
+ sizeof(void*) * cpu
,
185 KVADDR
, &rchan_buf
, sizeof(void*),
186 "rchan.buf", FAULT_ON_ERROR
);
187 readmem(rchan_buf
+ rchan_offsets
.buf_start
,
188 KVADDR
, &pcd
->buf
.start
, sizeof(void*),
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
);
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
);
214 static ulong
get_rchan_addr(ulong stp_relay_data
)
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.
224 if ((offset
= MEMBER_OFFSET("_stp_relay_data_type", "flushing")) > 0) {
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
235 * struct _stp_relay_data_type {
236 * struct rchan *rchan;
240 * If the definision of struct _stp_relay_data_type changes,
241 * we must check if this code is correct.
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"
245 "You may not be able to retrieve the correct trace data.\n");
249 return (stp_relay_data
+ (ulong
)offset
);
252 static int check_global_buffer(ulong rchan
)
257 for (cpu
= 0; cpu
< 2; cpu
++) {
258 readmem(rchan
+ rchan_offsets
.buf
+ sizeof(void*) * cpu
,
259 KVADDR
, &rchan_buf
[cpu
], sizeof(void*),
260 "rchan.buf", FAULT_ON_ERROR
);
262 if (rchan_buf
[0] == rchan_buf
[1])
267 static void setup_global_data(char *module
)
270 ulong stp_relay_data
= 0;
271 ulong stp_rchan_addr
= 0;
274 stp_relay_data
= symbol_value_module("_stp_relay_data", module
);
275 if (stp_relay_data
== 0) {
277 "Failed to find _stp_relay_data in module '%s'.\n",
281 stp_rchan_addr
= get_rchan_addr(stp_relay_data
);
282 if (stp_rchan_addr
== 0) {
284 "Failed to find '_stp_relay_data' in module '%s'.\n",
288 rchan
= get_rchan(stp_rchan_addr
);
289 for (i
= 0; i
< kt
->cpus
; i
++)
290 get_rchan_buf(i
, rchan
);
293 is_global
= check_global_buffer(rchan
);
298 static void create_output_filename(char *buf
, int len
, int cpu
)
301 snprintf(buf
, len
, "global");
303 snprintf(buf
, len
, "cpu%d", cpu
);
307 static void create_output_dir(const char *dirname
)
310 dir
= opendir(dirname
);
314 if (mkdir(dirname
, S_IRWXU
) < 0) {
315 error(FATAL
, "cannot create log directory '%s\n'", dirname
);
320 static FILE *open_output_file(const char *dname
, const char *fname
)
325 output_file
= GETBUF(sizeof(char) * (strlen(dname
) + strlen(fname
) + 2));
326 if (output_file
== NULL
) {
328 "cannot allocate memory for logfile name '%s%s'\n",
332 create_output_dir(dname
);
333 sprintf(output_file
,"%s/%s", dname
, fname
);
335 filp
= fopen(output_file
, "w");
337 error(FATAL
, "cannot create log file '%s'\n", output_file
);
339 FREEBUF(output_file
);
344 #define MAX_FNAME 128
346 static void output_cpu_logs(char *dirname
)
349 struct per_cpu_data
*pcd
;
350 size_t n
, idx
, start
, end
, len
;
352 char *source
, fname
[MAX_FNAME
+ 1];
354 /* allocate subbuf memory */
355 subbuf
= GETBUF(chan
.subbuf_size
);
357 error(FATAL
, "cannot allocate memory\n");
360 for (i
= 0; i
< kt
->cpus
; i
++) {
363 if (pcd
->buf
.subbufs_produced
== 0 && pcd
->buf
.offset
== 0) {
364 if (is_global
== 1) {
365 error(WARNING
, "There is no data in the relay buffer.\n");
368 error(WARNING
, "[cpu:%d]There is no data in the relay buffer.\n", i
);
373 end
= pcd
->buf
.subbufs_produced
+ 1;
374 if (pcd
->buf
.subbufs_produced
>= chan
.n_subbufs
) {
375 start
= end
- chan
.n_subbufs
;
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
,
387 (long)(start
% chan
.n_subbufs
),
389 (long)((end
-1) % chan
.n_subbufs
),
390 (long) pcd
->buf
.offset
);
391 outfp
= open_output_file(dirname
, fname
);
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
;
397 if (old_format
== 1) {
398 readmem((ulong
)pcd
->buf
.padding
+ sizeof(unsigned) * idx
,
399 KVADDR
, &padding
, sizeof(unsigned),
400 "padding", FAULT_ON_ERROR
);
402 readmem((ulong
)pcd
->buf
.padding
+ sizeof(padding
) * idx
,
403 KVADDR
, &padding
, sizeof(padding
),
404 "padding", FAULT_ON_ERROR
);
407 len
= pcd
->buf
.offset
;
409 len
= chan
.subbuf_size
;
412 if (old_format
== 1) {
413 source
+= sizeof(unsigned int);
414 len
-= sizeof(unsigned int) + padding
;
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");
430 * -a option retrieve the old data of subbuffer where the
431 * probe record is written at that time.
433 if (retrieve_all
== 1 && start
!= 0) {
434 strncat(fname
, ".may_broken", MAX_FNAME
);
435 fprintf(fp
, "--- generating '%s/%s' ---\n", dirname
, fname
);
436 fprintf(fp
, " read subbuf %ld(%ld) (offset:%ld-%ld)\n",
438 (long)((start
-1) % chan
.n_subbufs
),
439 (long)pcd
->buf
.offset
,
440 (long)chan
.subbuf_size
);
441 outfp
= open_output_file(dirname
, fname
);
443 idx
= (start
- 1) % chan
.n_subbufs
;
444 source
= pcd
->buf
.start
+ idx
* chan
.subbuf_size
+
446 len
= chan
.subbuf_size
- pcd
->buf
.offset
;
448 readmem((ulong
)source
, KVADDR
, subbuf
, len
,
449 "may_broken_subbuf", FAULT_ON_ERROR
);
450 if (fwrite(subbuf
, len
, 1, outfp
) != 1) {
452 "cannot write log data(may_broken)\n");
468 void cmd_staplog(void)
473 char *dirname
= NULL
;
475 while ((c
= getopt(argcnt
, args
, "+ao:")) != EOF
) {
488 module
= args
[optind
];
490 if (!module
|| argerrs
)
491 cmd_usage(pc
->curcmd
, SYNOPSIS
);
493 if (dirname
== NULL
&& module
!= NULL
)
496 setup_global_data(module
);
498 output_cpu_logs(dirname
);
502 void cmd_staplog_cleanup(void)
511 char *help_staplog
[] = {
513 "Retrieve SystemTap log data",
514 "[-a] [-o dir_name] module_name",
515 " Retrieve SystemTap's log data and write them to files.\n",
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",
520 " subbuffer may not be retrieved. But -a option retrieves these data",
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..",
525 " ...cpuN. This command doesn't change the log data format, but remove",
528 " -a Retrieve the old data which is recorded in",
529 " current written subbuffer and create another files",
530 " which have the special postfix `.may_broken`",
532 " -o file_name Specify the output directory.",
536 char *help_staplog_cleanup
[] = {
537 "systemtaplog cleanup (hidden)",
538 "Cleanup command for staplog",
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.",
546 static void __attribute__ ((constructor
)) _init(void)
549 register_extension(command_table
);
554 static void __attribute__ ((destructor
)) _fini(void)