]>
Commit | Line | Data |
---|---|---|
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 |
57 | struct 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 | ||
67 | struct fake_rchan_buf { | |
68 | void *start; | |
69 | size_t offset; | |
70 | size_t subbufs_produced; | |
71 | size_t *padding; | |
72 | }; | |
73 | ||
74 | struct fake_rchan { | |
75 | size_t subbuf_size; | |
76 | size_t n_subbufs; | |
77 | }; | |
78 | ||
79 | struct per_cpu_data { | |
80 | struct fake_rchan_buf buf; | |
81 | }; | |
82 | ||
83 | static struct rchan_offsets rchan_offsets; | |
84 | static struct fake_rchan chan; | |
85 | static struct per_cpu_data per_cpu[NR_CPUS]; | |
982b7e15 MH |
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; | |
35a04c8e FCE |
91 | |
92 | void cmd_staplog(void); | |
93 | void cmd_staplog_cleanup(void); | |
94 | char *help_staplog[]; | |
95 | char *help_staplog_cleanup[]; | |
96 | ||
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}, | |
101 | }; | |
102 | ||
103 | static 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; | |
128 | ERR: | |
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 | ||
153 | static 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 | 178 | static 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 | 214 | static 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 | ||
252 | static 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 | 267 | static 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 | 298 | static 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 | 307 | static 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 | 320 | static 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 | 346 | static 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 |
468 | void 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 | ||
502 | void cmd_staplog_cleanup(void) | |
503 | { | |
504 | if (outfp) { | |
505 | fclose(outfp); | |
506 | outfp = NULL; | |
507 | } | |
508 | return; | |
509 | } | |
510 | ||
511 | char *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 | ||
536 | char *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 | 546 | static void __attribute__ ((constructor)) _init(void) |
35a04c8e FCE |
547 | { |
548 | get_rchan_offsets(); | |
549 | register_extension(command_table); | |
550 | return; | |
551 | } | |
552 | ||
553 | ||
554 | static void __attribute__ ((destructor)) _fini(void) | |
555 | { | |
556 | return; | |
557 | } |