]> sourceware.org Git - systemtap.git/blame - staplog.c
PR 9716, replaced pkgconfig checks with AC macros in configure.ac for server deps.
[systemtap.git] / staplog.c
CommitLineData
35a04c8e
FCE
1/*
2 crash shared object for retrieving systemtap buffer
982b7e15 3 Copyright (c) 2007, Hitachi, Ltd.,
1673e81e 4 Created by Satoru Moriya <satoru.moriya.br@hitachi.com>
982b7e15
MH
5 Updated by Masami Hiramatsu <mhiramat@redhat.com>
6
35a04c8e
FCE
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
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
982b7e15 127static ulong get_rchan(ulong chan_addr)
35a04c8e
FCE
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
982b7e15 142static void get_rchan_buf(int cpu, ulong rchan)
35a04c8e
FCE
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];
982b7e15 204
35a04c8e
FCE
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
982b7e15 215static void setup_global_data(char *module)
35a04c8e
FCE
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
982b7e15 247static void create_output_filename(char *buf, int len, int cpu)
1673e81e 248{
1673e81e 249 if (is_global) {
982b7e15 250 snprintf(buf, len, "global");
1673e81e 251 } else {
982b7e15 252 snprintf(buf, len, "cpu%d", cpu);
1673e81e 253 }
1673e81e
MH
254}
255
982b7e15 256static void create_output_dir(const char *dirname)
1673e81e
MH
257{
258 DIR *dir;
259 dir = opendir(dirname);
260 if (dir) {
261 closedir(dir);
262 } else {
263 if (mkdir(dirname, S_IRWXU) < 0) {
264 error(FATAL, "cannot create log directory '%s\n'", dirname);
265 }
266 }
267}
268
982b7e15 269static FILE *open_output_file(const char *dname, const char *fname)
1673e81e
MH
270{
271 FILE *filp = NULL;
272 char *output_file;
1673e81e 273
982b7e15
MH
274 output_file = GETBUF(sizeof(char) * (strlen(dname) + strlen(fname) + 2));
275 if (output_file == NULL) {
276 error(FATAL, "cannot allocate memory for logfile name\n");
277 }
1673e81e
MH
278
279 create_output_dir(dname);
280 sprintf(output_file,"%s/%s", dname, fname);
281
282 filp = fopen(output_file, "w");
283 if (!filp) {
284 error(FATAL, "cannot create log file '%s'\n", output_file);
285 }
982b7e15 286 FREEBUF(output_file);
1673e81e
MH
287
288 return filp;
289}
290
982b7e15
MH
291#define MAX_FNAME 128
292
faf96009 293static void output_cpu_logs(char *dirname)
35a04c8e 294{
1673e81e 295 int i;
35a04c8e 296 struct per_cpu_data *pcd;
1673e81e 297 size_t n, idx, start, end, len;
faf96009 298 size_t padding;
982b7e15 299 char *source, fname[MAX_FNAME + 1];
35a04c8e 300
35a04c8e
FCE
301 /* allocate subbuf memory */
302 subbuf = GETBUF(chan.subbuf_size);
303 if (!subbuf) {
304 error(FATAL, "cannot allocate memory\n");
305 }
306
35a04c8e 307 for (i = 0; i < kt->cpus; i++) {
35a04c8e
FCE
308 pcd = &per_cpu[i];
309
1673e81e 310 if (pcd->buf.subbufs_produced == 0 && pcd->buf.offset == 0) {
faf96009
FCE
311 if (is_global == 1) {
312 error(WARNING, "There is no data in the relay buffer.\n");
313 break;
314 } else {
315 error(WARNING, "[cpu:%d]There is no data in the relay buffer.\n", i);
316 continue;
317 }
318 }
35a04c8e 319
982b7e15 320 end = pcd->buf.subbufs_produced + 1;
1673e81e 321 if (pcd->buf.subbufs_produced >= chan.n_subbufs) {
982b7e15 322 start = end - chan.n_subbufs;
35a04c8e
FCE
323 } else {
324 start = 0;
35a04c8e 325 }
1673e81e 326
982b7e15
MH
327 create_output_filename(fname, MAX_FNAME, i);
328 fprintf(fp, "--- generating '%s/%s' ---\n", dirname, fname);
329 fprintf(fp, " subbufs ready on relayfs:%ld\n", (long)end);
330 fprintf(fp, " n_subbufs:%ld, read subbuf from:%ld(%ld) "
331 "to:%ld(%ld) (offset:0-%ld)\n\n",
332 (long)chan.n_subbufs,
333 (long)start,
334 (long)(start % chan.n_subbufs),
335 (long)end-1,
336 (long)((end-1) % chan.n_subbufs),
337 (long) pcd->buf.offset);
1673e81e
MH
338 outfp = open_output_file(dirname, fname);
339
35a04c8e
FCE
340 for (n = start; n < end; n++) {
341 /* read relayfs subbufs and write to log file */
342 idx = n % chan.n_subbufs;
343 source = pcd->buf.start + idx * chan.subbuf_size;
344 readmem((ulong)pcd->buf.padding + sizeof(padding) * idx,
345 KVADDR, &padding, sizeof(padding),
346 "padding", FAULT_ON_ERROR);
982b7e15 347 if (n == end - 1) {
35a04c8e
FCE
348 len = pcd->buf.offset;
349 } else {
350 len = chan.subbuf_size;
982b7e15 351 }
35a04c8e 352 if (old_format == 1) {
1673e81e
MH
353 source += sizeof(unsigned int);
354 len -= sizeof(unsigned int) + padding;
35a04c8e
FCE
355 } else {
356 len -= padding;
357 }
982b7e15 358 if (len > 0) {
35a04c8e
FCE
359 readmem((ulong)source, KVADDR, subbuf, len,
360 "subbuf", FAULT_ON_ERROR);
361 if (fwrite(subbuf, len, 1, outfp) != 1) {
362 error(FATAL, "cannot write log data\n");
363 }
364 }
365 }
366 fclose(outfp);
367 outfp = NULL;
1673e81e
MH
368
369 /*
982b7e15 370 * -a option retrieve the old data of subbuffer where the
1673e81e
MH
371 * probe record is written at that time.
372 */
982b7e15
MH
373 if (retrieve_all == 1 && start != 0) {
374 strncat(fname, ".may_broken", MAX_FNAME);
375 fprintf(fp, "--- generating '%s/%s' ---\n", dirname, fname);
376 fprintf(fp, " read subbuf %ld(%ld) (offset:%ld-%ld)\n",
377 (long)start-1,
378 (long)((start-1) % chan.n_subbufs),
379 (long)pcd->buf.offset,
380 (long)chan.subbuf_size);
1673e81e 381 outfp = open_output_file(dirname, fname);
982b7e15
MH
382
383 idx = (start - 1) % chan.n_subbufs;
384 source = pcd->buf.start + idx * chan.subbuf_size +
1673e81e 385 pcd->buf.offset;
1673e81e
MH
386 len = chan.subbuf_size - pcd->buf.offset;
387 if (len) {
388 readmem((ulong)source, KVADDR, subbuf, len,
389 "may_broken_subbuf", FAULT_ON_ERROR);
390 if(fwrite(subbuf, len, 1, outfp) != 1) {
982b7e15 391 error(FATAL,
1673e81e
MH
392 "cannot write log data(may_broken)\n");
393 }
394 }
395 fclose(outfp);
396 outfp = NULL;
1673e81e 397 }
35a04c8e
FCE
398 if (is_global == 1)
399 break;
400 }
401 if (subbuf) {
402 FREEBUF(subbuf);
403 subbuf = NULL;
404 }
405 return;
406}
407
35a04c8e
FCE
408void cmd_staplog(void)
409{
410
411 int c;
412 char *module = NULL;
faf96009 413 char *dirname = NULL;
35a04c8e 414
1673e81e 415 while ((c = getopt(argcnt, args, "+ao:")) != EOF) {
35a04c8e 416 switch (c) {
1673e81e
MH
417 case 'a':
418 retrieve_all = 1;
419 break;
35a04c8e 420 case 'o':
faf96009 421 dirname = optarg;
35a04c8e
FCE
422 break;
423 default:
424 argerrs++;
425 break;
426 }
427 }
428 module = args[optind];
429
430 if (!module || argerrs)
431 cmd_usage(pc->curcmd, SYNOPSIS);
432
faf96009
FCE
433 if (dirname == NULL && module != NULL)
434 dirname = module;
982b7e15
MH
435
436 setup_global_data(module);
437 output_cpu_logs(dirname);
35a04c8e
FCE
438 return;
439}
440
441void cmd_staplog_cleanup(void)
442{
443 if (outfp) {
444 fclose(outfp);
445 outfp = NULL;
446 }
447 return;
448}
449
450char *help_staplog[] = {
451 "systemtaplog",
452 "Retrieve SystemTap log data",
1673e81e 453 "[-a] [-o dir_name] module_name",
35a04c8e 454 " Retrieve SystemTap's log data and write them to files.\n",
1673e81e
MH
455 " All valid SystemTap's log data made by the trace module which name",
456 " is 'module_name' are written into log files. This command starts",
457 " to retrieve log data from the subbuffer which is next to current",
458 " written subbuffer. Therefore some old data in the current written",
982b7e15 459 " subbuffer may not be retrieved. But -a option retrieves these data",
1673e81e
MH
460 " and write them into another log file which have the special ",
461 " postfix `.may_broken`.",
462 " If you don't use -o option, the log files are created in",
463 " `module_name` directory. The name of each log file is cpu0, cpu1..",
982b7e15 464 " ...cpuN. This command doesn't change the log data format, but remove",
1673e81e 465 " only padding.",
35a04c8e 466 "",
1673e81e 467 " -a Retrieve the old data which is recorded in",
982b7e15
MH
468 " current written subbuffer and create another files",
469 " which have the special postfix `.may_broken`",
1673e81e 470 " for these data.",
35a04c8e
FCE
471 " -o file_name Specify the output directory.",
472 NULL,
473};
474
475char *help_staplog_cleanup[] = {
476 "systemtaplog cleanup (hidden)",
477 "Cleanup command for staplog",
478 "",
479 " This command is called during restore_sanity() prior to each ",
480 " command prompt to close the files which was opened and failed to",
481 " close by staplog command.",
482 NULL,
483};
484
982b7e15 485static void __attribute__ ((constructor)) _init(void)
35a04c8e
FCE
486{
487 get_rchan_offsets();
488 register_extension(command_table);
489 return;
490}
491
492
493static void __attribute__ ((destructor)) _fini(void)
494{
495 return;
496}
This page took 0.093324 seconds and 5 git commands to generate.