doc/man: convert lttng-crash(1) to AsciiDoc
[lttng-tools.git] / src / bin / lttng-crash / lttng-crash.c
CommitLineData
d7ba1388
MD
1/*
2 * Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
3 * Copyright (C) 2014 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License, version 2 only,
7 * as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
d7ba1388
MD
19#include <getopt.h>
20#include <signal.h>
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24#include <sys/stat.h>
25#include <sys/types.h>
26#include <sys/stat.h>
27#include <sys/mman.h>
28#include <fcntl.h>
29#include <sys/wait.h>
30#include <unistd.h>
d7ba1388
MD
31#include <ctype.h>
32#include <dirent.h>
33#include <byteswap.h>
34#include <inttypes.h>
aa25d686 35#include <stdbool.h>
d7ba1388
MD
36
37#include <version.h>
38#include <lttng/lttng.h>
39#include <common/common.h>
40
41#define DEFAULT_VIEWER "babeltrace"
42
43#define COPY_BUFLEN 4096
44#define RB_CRASH_DUMP_ABI_LEN 32
45
46#define RB_CRASH_DUMP_ABI_MAGIC_LEN 16
47
48/*
49 * The 128-bit magic number is xor'd in the process data so it does not
50 * cause a false positive when searching for buffers by scanning memory.
51 * The actual magic number is:
52 * 0x17, 0x7B, 0xF1, 0x77, 0xBF, 0x17, 0x7B, 0xF1,
53 * 0x77, 0xBF, 0x17, 0x7B, 0xF1, 0x77, 0xBF, 0x17,
54 */
55#define RB_CRASH_DUMP_ABI_MAGIC_XOR \
56 { \
57 0x17 ^ 0xFF, 0x7B ^ 0xFF, 0xF1 ^ 0xFF, 0x77 ^ 0xFF, \
58 0xBF ^ 0xFF, 0x17 ^ 0xFF, 0x7B ^ 0xFF, 0xF1 ^ 0xFF, \
59 0x77 ^ 0xFF, 0xBF ^ 0xFF, 0x17 ^ 0xFF, 0x7B ^ 0xFF, \
60 0xF1 ^ 0xFF, 0x77 ^ 0xFF, 0xBF ^ 0xFF, 0x17 ^ 0xFF, \
61 }
62
63/*
64 * Non-static to ensure the compiler does not optimize away the xor.
65 */
66uint8_t lttng_crash_expected_magic_xor[] = RB_CRASH_DUMP_ABI_MAGIC_XOR;
67
68#define RB_CRASH_ENDIAN 0x1234
69#define RB_CRASH_ENDIAN_REVERSE 0x3412
70
71enum lttng_crash_type {
72 LTTNG_CRASH_TYPE_UST = 0,
73 LTTNG_CRASH_TYPE_KERNEL = 1,
74};
75
76/* LTTng ring buffer defines (copied) */
77
78#define HALF_ULONG_BITS(wl) (((wl) * CHAR_BIT) >> 1)
79
80#define SB_ID_OFFSET_SHIFT(wl) (HALF_ULONG_BITS(wl) + 1)
81#define SB_ID_OFFSET_COUNT(wl) (1UL << SB_ID_OFFSET_SHIFT(wl))
82#define SB_ID_OFFSET_MASK(wl) (~(SB_ID_OFFSET_COUNT(wl) - 1))
83/*
84 * Lowest bit of top word half belongs to noref. Used only for overwrite mode.
85 */
86#define SB_ID_NOREF_SHIFT(wl) (SB_ID_OFFSET_SHIFT(wl) - 1)
87#define SB_ID_NOREF_COUNT(wl) (1UL << SB_ID_NOREF_SHIFT(wl))
88#define SB_ID_NOREF_MASK(wl) SB_ID_NOREF_COUNT(wl)
89/*
90 * In overwrite mode: lowest half of word is used for index.
91 * Limit of 2^16 subbuffers per buffer on 32-bit, 2^32 on 64-bit.
92 * In producer-consumer mode: whole word used for index.
93 */
94#define SB_ID_INDEX_SHIFT(wl) 0
95#define SB_ID_INDEX_COUNT(wl) (1UL << SB_ID_INDEX_SHIFT(wl))
96#define SB_ID_INDEX_MASK(wl) (SB_ID_NOREF_COUNT(wl) - 1)
97
98enum rb_modes {
99 RING_BUFFER_OVERWRITE = 0, /* Overwrite when buffer full */
100 RING_BUFFER_DISCARD = 1, /* Discard when buffer full */
101};
102
103struct crash_abi_unknown {
104 uint8_t magic[RB_CRASH_DUMP_ABI_MAGIC_LEN];
8726a045 105 uint64_t mmap_length; /* Overall length of crash record */
d7ba1388
MD
106 uint16_t endian; /*
107 * { 0x12, 0x34 }: big endian
108 * { 0x34, 0x12 }: little endian
109 */
110 uint16_t major; /* Major number. */
111 uint16_t minor; /* Minor number. */
112 uint8_t word_size; /* Word size (bytes). */
113 uint8_t layout_type; /* enum lttng_crash_layout */
114} __attribute__((packed));
115
116struct crash_abi_0_0 {
117 struct crash_abi_unknown parent;
118
119 struct {
120 uint32_t prod_offset;
121 uint32_t consumed_offset;
122 uint32_t commit_hot_array;
123 uint32_t commit_hot_seq;
124 uint32_t buf_wsb_array;
125 uint32_t buf_wsb_id;
126 uint32_t sb_array;
127 uint32_t sb_array_shmp_offset;
128 uint32_t sb_backend_p_offset;
129 uint32_t content_size;
130 uint32_t packet_size;
131 } __attribute__((packed)) offset;
132 struct {
133 uint8_t prod_offset;
134 uint8_t consumed_offset;
135 uint8_t commit_hot_seq;
136 uint8_t buf_wsb_id;
137 uint8_t sb_array_shmp_offset;
138 uint8_t sb_backend_p_offset;
139 uint8_t content_size;
140 uint8_t packet_size;
141 } __attribute__((packed)) length;
142 struct {
143 uint32_t commit_hot_array;
144 uint32_t buf_wsb_array;
145 uint32_t sb_array;
146 } __attribute__((packed)) stride;
147
148 uint64_t buf_size; /* Size of the buffer */
149 uint64_t subbuf_size; /* Sub-buffer size */
150 uint64_t num_subbuf; /* Number of sub-buffers for writer */
151 uint32_t mode; /* Buffer mode: 0: overwrite, 1: discard */
152} __attribute__((packed));
153
154struct lttng_crash_layout {
155 struct {
156 int prod_offset, consumed_offset,
157 commit_hot_array, commit_hot_seq,
158 buf_wsb_array, buf_wsb_id,
159 sb_array, sb_array_shmp_offset,
160 sb_backend_p_offset, content_size,
161 packet_size;
162 } offset;
163 struct {
164 int prod_offset, consumed_offset,
165 commit_hot_seq, buf_wsb_id,
166 sb_array_shmp_offset, sb_backend_p_offset,
167 content_size, packet_size;
168 } length;
169 struct {
170 int commit_hot_array, buf_wsb_array, sb_array;
171 } stride;
172
173 int reverse_byte_order;
174 int word_size;
175
176 uint64_t mmap_length; /* Length of crash record */
177 uint64_t buf_size; /* Size of the buffer */
178 uint64_t subbuf_size; /* Sub-buffer size */
179 uint64_t num_subbuf; /* Number of sub-buffers for writer */
180 uint32_t mode; /* Buffer mode: 0: overwrite, 1: discard */
181};
182
183/* Variables */
184static char *progname,
9030e9a9
AB
185 *opt_viewer_path = NULL,
186 *opt_output_path = NULL;
d7ba1388 187
a424227e 188static char *input_path;
d7ba1388
MD
189
190int lttng_opt_quiet, lttng_opt_verbose, lttng_opt_mi;
191
192enum {
193 OPT_DUMP_OPTIONS,
194};
195
196/* Getopt options. No first level command. */
197static struct option long_options[] = {
198 { "version", 0, NULL, 'V' },
199 { "help", 0, NULL, 'h' },
200 { "verbose", 0, NULL, 'v' },
201 { "viewer", 1, NULL, 'e' },
202 { "extract", 1, NULL, 'x' },
203 { "list-options", 0, NULL, OPT_DUMP_OPTIONS },
204 { NULL, 0, NULL, 0 },
205};
206
207static void usage(FILE *ofp)
208{
209 fprintf(ofp, "LTTng Crash Trace Viewer " VERSION " - " VERSION_NAME "%s\n\n",
210 GIT_VERSION[0] == '\0' ? "" : " - " GIT_VERSION);
acade31f 211 fprintf(ofp, "usage: lttng-crash [OPTIONS] FILE\n");
d7ba1388
MD
212 fprintf(ofp, "\n");
213 fprintf(ofp, "Options:\n");
214 fprintf(ofp, " -V, --version Show version.\n");
215 fprintf(ofp, " -h, --help Show this help.\n");
216 fprintf(ofp, " --list-options Simple listing of lttng-crash options.\n");
217 fprintf(ofp, " -v, --verbose Increase verbosity.\n");
218 fprintf(ofp, " -e, --viewer Specify viewer and/or options to use. This will\n"
219 " completely override the default viewers so please\n"
220 " make sure to specify the full command. The trace\n"
221 " directory paths appended at the end to the\n"
222 " arguments.\n");
223 fprintf(ofp, " -x, --extract PATH Extract trace(s) to specified path. Don't view\n"
224 " trace.\n");
225 fprintf(ofp, "\n");
226 fprintf(ofp, "Please see the lttng-crash(1) man page for full documentation.\n");
227 fprintf(ofp, "See http://lttng.org for updates, bug reports and news.\n");
228}
229
230static void version(FILE *ofp)
231{
232 fprintf(ofp, "%s (LTTng Crash Trace Viewer) " VERSION " - " VERSION_NAME
233"%s\n",
234 progname,
235 GIT_VERSION[0] == '\0' ? "" : " - " GIT_VERSION);
236}
237
238/*
239 * list_options
240 *
241 * List options line by line. This is mostly for bash auto completion and to
242 * avoid difficult parsing.
243 */
244static void list_options(FILE *ofp)
245{
246 int i = 0;
247 struct option *option = NULL;
248
249 option = &long_options[i];
250 while (option->name != NULL) {
251 fprintf(ofp, "--%s\n", option->name);
252
253 if (isprint(option->val)) {
254 fprintf(ofp, "-%c\n", option->val);
255 }
256
257 i++;
258 option = &long_options[i];
259 }
260}
261
262/*
263 * Parse command line arguments.
264 *
265 * Return 0 if OK, else -1
266 */
267static int parse_args(int argc, char **argv)
268{
269 int opt, ret = 0;
270
271 if (argc < 2) {
272 usage(stderr);
273 exit(EXIT_FAILURE);
274 }
275
d07f3d99 276 while ((opt = getopt_long(argc, argv, "+Vhve:x:", long_options, NULL)) != -1) {
d7ba1388
MD
277 switch (opt) {
278 case 'V':
279 version(stdout);
280 ret = 1;
281 goto end;
282 case 'h':
283 usage(stdout);
284 ret = 1;
285 goto end;
286 case 'v':
287 /* There is only 3 possible level of verbosity. (-vvv) */
288 if (lttng_opt_verbose < 3) {
289 lttng_opt_verbose += 1;
290 }
291 break;
292 case 'e':
9030e9a9 293 free(opt_viewer_path);
d7ba1388
MD
294 opt_viewer_path = strdup(optarg);
295 break;
296 case 'x':
9030e9a9 297 free(opt_output_path);
d7ba1388
MD
298 opt_output_path = strdup(optarg);
299 break;
300 case OPT_DUMP_OPTIONS:
301 list_options(stdout);
302 ret = 1;
303 goto end;
304 default:
305 usage(stderr);
306 goto error;
307 }
308 }
309
9030e9a9
AB
310 if (!opt_viewer_path) {
311 opt_viewer_path = DEFAULT_VIEWER;
312 }
313
a424227e
MD
314 /* No leftovers, or more than one input path, print usage and quit */
315 if ((argc - optind) == 0 || (argc - optind) > 1) {
d7ba1388
MD
316 usage(stderr);
317 goto error;
318 }
319
a424227e 320 input_path = argv[optind];
d7ba1388
MD
321end:
322 return ret;
323
324error:
325 return -1;
326}
327
328static
329int copy_file(const char *file_dest, const char *file_src)
330{
8726a045 331 int fd_src = -1, fd_dest = -1;
d7ba1388
MD
332 ssize_t readlen, writelen;
333 char buf[COPY_BUFLEN];
8726a045 334 int ret;
d7ba1388
MD
335
336 DBG("Copy metadata file '%s' into '%s'", file_src, file_dest);
337
338 fd_src = open(file_src, O_RDONLY);
339 if (fd_src < 0) {
340 PERROR("Error opening %s for reading", file_src);
8726a045
JR
341 ret = -errno;
342 goto error;
d7ba1388
MD
343 }
344 fd_dest = open(file_dest, O_RDWR | O_CREAT | O_EXCL,
345 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
346 if (fd_dest < 0) {
347 PERROR("Error opening %s for writing", file_dest);
8726a045
JR
348 ret = -errno;
349 goto error;
d7ba1388
MD
350 }
351
352 for (;;) {
353 readlen = lttng_read(fd_src, buf, COPY_BUFLEN);
354 if (readlen < 0) {
355 PERROR("Error reading input file");
8726a045
JR
356 ret = -1;
357 goto error;
d7ba1388
MD
358 }
359 if (!readlen) {
360 break;
361 }
362 writelen = lttng_write(fd_dest, buf, readlen);
363 if (writelen < readlen) {
364 PERROR("Error writing to output file");
8726a045
JR
365 ret = -1;
366 goto error;
367 }
368 }
369
370 ret = 0;
371error:
372 if (fd_src >= 0) {
373 if (close(fd_src) < 0) {
374 PERROR("Error closing %s", file_src);
375 }
376 }
377
378 if (fd_dest >= 0) {
379 if (close(fd_dest) < 0) {
380 PERROR("Error closing %s", file_dest);
d7ba1388
MD
381 }
382 }
8726a045 383 return ret;
d7ba1388
MD
384}
385
386static
387uint64_t _crash_get_field(const struct lttng_crash_layout *layout,
388 const char *ptr, size_t size)
389{
390 switch (size) {
391 case 1: return *(uint8_t *) ptr;
392 case 2: if (layout->reverse_byte_order) {
393 return __bswap_16(*(uint16_t *) ptr);
394 } else {
395 return *(uint16_t *) ptr;
396
397 }
398 case 4: if (layout->reverse_byte_order) {
399 return __bswap_32(*(uint32_t *) ptr);
400 } else {
401 return *(uint32_t *) ptr;
402
403 }
404 case 8: if (layout->reverse_byte_order) {
405 return __bswap_64(*(uint64_t *) ptr);
406 } else {
407 return *(uint64_t *) ptr;
408 }
409 default:
410 abort();
411 return -1;
412 }
413
414}
415
416#define crash_get_field(layout, map, name) \
417 _crash_get_field(layout, (map) + (layout)->offset.name, \
418 layout->length.name)
419
420#define crash_get_array_field(layout, map, array_name, idx, field_name) \
421 _crash_get_field(layout, \
422 (map) + (layout)->offset.array_name \
423 + (idx * (layout)->stride.array_name) \
424 + (layout)->offset.field_name, \
425 (layout)->length.field_name)
426
427#define crash_get_hdr_raw_field(layout, hdr, name) ((hdr)->name)
428
429#define crash_get_hdr_field(layout, hdr, name) \
430 _crash_get_field(layout, (const char *) &(hdr)->name, \
431 sizeof((hdr)->name))
432
433#define crash_get_layout(layout, hdr, name) \
434 do { \
435 (layout)->name = crash_get_hdr_field(layout, hdr, \
436 name); \
437 DBG("layout.%s = %" PRIu64, #name, \
438 (uint64_t) (layout)->name); \
439 } while (0)
440
441static
442int get_crash_layout_0_0(struct lttng_crash_layout *layout,
443 char *map)
444{
445 const struct crash_abi_0_0 *abi = (const struct crash_abi_0_0 *) map;
446
447 crash_get_layout(layout, abi, offset.prod_offset);
448 crash_get_layout(layout, abi, offset.consumed_offset);
449 crash_get_layout(layout, abi, offset.commit_hot_array);
450 crash_get_layout(layout, abi, offset.commit_hot_seq);
451 crash_get_layout(layout, abi, offset.buf_wsb_array);
452 crash_get_layout(layout, abi, offset.buf_wsb_id);
453 crash_get_layout(layout, abi, offset.sb_array);
454 crash_get_layout(layout, abi, offset.sb_array_shmp_offset);
455 crash_get_layout(layout, abi, offset.sb_backend_p_offset);
456 crash_get_layout(layout, abi, offset.content_size);
457 crash_get_layout(layout, abi, offset.packet_size);
458
459 crash_get_layout(layout, abi, length.prod_offset);
460 crash_get_layout(layout, abi, length.consumed_offset);
461 crash_get_layout(layout, abi, length.commit_hot_seq);
462 crash_get_layout(layout, abi, length.buf_wsb_id);
463 crash_get_layout(layout, abi, length.sb_array_shmp_offset);
464 crash_get_layout(layout, abi, length.sb_backend_p_offset);
465 crash_get_layout(layout, abi, length.content_size);
466 crash_get_layout(layout, abi, length.packet_size);
467
468 crash_get_layout(layout, abi, stride.commit_hot_array);
469 crash_get_layout(layout, abi, stride.buf_wsb_array);
470 crash_get_layout(layout, abi, stride.sb_array);
471
472 crash_get_layout(layout, abi, buf_size);
473 crash_get_layout(layout, abi, subbuf_size);
474 crash_get_layout(layout, abi, num_subbuf);
475 crash_get_layout(layout, abi, mode);
476
477 return 0;
478}
479
480static
481void print_dbg_magic(const uint8_t *magic)
482{
483 DBG("magic: 0x%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X",
484 magic[0], magic[1], magic[2], magic[3],
485 magic[4], magic[5], magic[6], magic[7],
486 magic[8], magic[9], magic[10], magic[11],
487 magic[12], magic[13], magic[14], magic[15]);
488}
489
490static
491int check_magic(const uint8_t *magic)
492{
493 int i;
494
495 for (i = 0; i < RB_CRASH_DUMP_ABI_MAGIC_LEN; i++) {
496 if ((magic[i] ^ 0xFF) != lttng_crash_expected_magic_xor[i]) {
497 return -1;
498 }
499 }
500 return 0;
501}
502
503static
504int get_crash_layout(struct lttng_crash_layout *layout, int fd)
505{
506 char *map;
507 int ret = 0, unmapret;
508 const uint8_t *magic;
509 uint64_t mmap_length;
510 uint16_t major, minor;
511 uint8_t word_size;
512 const struct crash_abi_unknown *abi;
513 uint16_t endian;
514 enum lttng_crash_type layout_type;
515
516 map = mmap(NULL, RB_CRASH_DUMP_ABI_LEN, PROT_READ, MAP_PRIVATE,
517 fd, 0);
518 if (map == MAP_FAILED) {
519 PERROR("Mapping file");
520 return -1;
521 }
522 abi = (const struct crash_abi_unknown *) map;
523 magic = crash_get_hdr_raw_field(layout, abi, magic);
524 print_dbg_magic(magic);
525 if (check_magic(magic)) {
526 DBG("Unknown magic number");
527 ret = 1; /* positive return value, skip */
528 goto end;
529 }
530 endian = crash_get_hdr_field(layout, abi, endian);
531 switch (endian) {
532 case RB_CRASH_ENDIAN:
533 break;
534 case RB_CRASH_ENDIAN_REVERSE:
535 layout->reverse_byte_order = 1;
536 break;
537 default:
538 DBG("Unknown endianness value: 0x%X", (unsigned int) endian);
539 ret = 1; /* positive return value, skip */
540 goto end;
541 }
542 layout_type = (enum lttng_crash_type) crash_get_hdr_field(layout, abi, layout_type);
543 switch (layout_type) {
544 case LTTNG_CRASH_TYPE_UST:
545 break;
546 case LTTNG_CRASH_TYPE_KERNEL:
547 ERR("lttng-modules buffer layout support not implemented");
548 ret = 1; /* positive return value, skip */
549 goto end;
550 default:
551 ERR("Unknown layout type %u", (unsigned int) layout_type);
552 ret = 1; /* positive return value, skip */
553 goto end;
554 }
555 mmap_length = crash_get_hdr_field(layout, abi, mmap_length);
556 DBG("mmap_length: %" PRIu64, mmap_length);
557 layout->mmap_length = mmap_length;
558 major = crash_get_hdr_field(layout, abi, major);
559 DBG("major: %u", major);
560 minor = crash_get_hdr_field(layout, abi, minor);
561 DBG("minor: %u", minor);
562 word_size = crash_get_hdr_field(layout, abi, word_size);
563 DBG("word_size: %u", word_size);
564 switch (major) {
565 case 0:
566 switch (minor) {
567 case 0:
568 ret = get_crash_layout_0_0(layout, map);
569 if (ret)
570 goto end;
571 break;
572 default:
573 ret = -1;
574 ERR("Unsupported crash ABI %u.%u\n", major, minor);
575 goto end;
576 }
577 break;
578 default:
579 ERR("Unsupported crash ABI %u.%u\n", major, minor);
580 ret = -1;
581 goto end;
582 }
583 layout->word_size = word_size;
584end:
585 unmapret = munmap(map, RB_CRASH_DUMP_ABI_LEN);
586 if (unmapret) {
587 PERROR("munmap");
588 }
589 return ret;
590}
591
592/* buf_trunc mask selects only the buffer number. */
593static inline
594uint64_t buf_trunc(uint64_t offset, uint64_t buf_size)
595{
596 return offset & ~(buf_size - 1);
597}
598
599/* subbuf_trunc mask selects the subbuffer number. */
600static inline
601uint64_t subbuf_trunc(uint64_t offset, uint64_t subbuf_size)
602{
603 return offset & ~(subbuf_size - 1);
604}
605
606/* buf_offset mask selects only the offset within the current buffer. */
607static inline
608uint64_t buf_offset(uint64_t offset, uint64_t buf_size)
609{
610 return offset & (buf_size - 1);
611}
612
613/* subbuf_offset mask selects the offset within the current subbuffer. */
614static inline
615uint64_t subbuf_offset(uint64_t offset, uint64_t subbuf_size)
616{
617 return offset & (subbuf_size - 1);
618}
619
620/* subbuf_index returns the index of the current subbuffer within the buffer. */
621static inline
622uint64_t subbuf_index(uint64_t offset, uint64_t buf_size, uint64_t subbuf_size)
623{
624 return buf_offset(offset, buf_size) / subbuf_size;
625}
626
627static inline
628uint64_t subbuffer_id_get_index(uint32_t mode, uint64_t id,
629 unsigned int wl)
630{
631 if (mode == RING_BUFFER_OVERWRITE)
632 return id & SB_ID_INDEX_MASK(wl);
633 else
634 return id;
635}
636
637static
638int copy_crash_subbuf(const struct lttng_crash_layout *layout,
639 int fd_dest, char *buf, uint64_t offset)
640{
641 uint64_t buf_size, subbuf_size, num_subbuf, sbidx, id,
642 sb_bindex, rpages_offset, p_offset, seq_cc,
643 committed, commit_count_mask, consumed_cur,
644 packet_size;
645 char *subbuf_ptr;
646 ssize_t writelen;
647
648 /*
649 * Get the current subbuffer by applying the proper mask to
650 * "offset", and looking up the subbuf location within the
651 * source file buf.
652 */
653
654 buf_size = layout->buf_size;
655 subbuf_size = layout->subbuf_size;
656 num_subbuf = layout->num_subbuf;
657
658 switch (layout->word_size) {
659 case 4: commit_count_mask = 0xFFFFFFFFULL / num_subbuf;
660 break;
661 case 8: commit_count_mask = 0xFFFFFFFFFFFFFFFFULL / num_subbuf;
662 break;
663 default:
664 ERR("Unsupported word size: %u",
665 (unsigned int) layout->word_size);
666 return -EINVAL;
667 }
668
5f98d630 669 DBG("Copy crash subbuffer at offset %" PRIu64, offset);
d7ba1388
MD
670 sbidx = subbuf_index(offset, buf_size, subbuf_size);
671
672 /*
673 * Find where the seq cc is located. Compute length of data to
674 * copy.
675 */
676 seq_cc = crash_get_array_field(layout, buf, commit_hot_array,
677 sbidx, commit_hot_seq);
678 consumed_cur = crash_get_field(layout, buf, consumed_offset);
679
680 /*
681 * Check that the buffer we are getting is after or at
682 * consumed_cur position.
683 */
684 if ((long) subbuf_trunc(offset, subbuf_size)
685 - (long) subbuf_trunc(consumed_cur, subbuf_size) < 0) {
686 DBG("No data: position is before consumed_cur");
687 goto nodata;
688 }
689
690 /*
691 * Check if subbuffer has been fully committed.
692 */
693 if (((seq_cc - subbuf_size) & commit_count_mask)
694 - (buf_trunc(offset, buf_size) / num_subbuf)
695 == 0) {
696 committed = subbuf_size;
697 } else {
698 committed = subbuf_offset(seq_cc, subbuf_size);
699 if (!committed) {
700 DBG("No data committed, seq_cc: %" PRIu64, seq_cc);
701 goto nodata;
702 }
703 }
704
705 /* Find actual physical offset in subbuffer table */
706 id = crash_get_array_field(layout, buf, buf_wsb_array,
707 sbidx, buf_wsb_id);
708 sb_bindex = subbuffer_id_get_index(layout->mode, id,
709 layout->word_size);
710 rpages_offset = crash_get_array_field(layout, buf, sb_array,
711 sb_bindex, sb_array_shmp_offset);
712 p_offset = crash_get_field(layout, buf + rpages_offset,
713 sb_backend_p_offset);
714 subbuf_ptr = buf + p_offset;
715
716 if (committed == subbuf_size) {
717 /*
718 * Packet header can be used.
719 */
720 if (layout->length.packet_size) {
721 memcpy(&packet_size,
722 subbuf_ptr + layout->offset.packet_size,
723 layout->length.packet_size);
724 if (layout->reverse_byte_order) {
725 packet_size = __bswap_64(packet_size);
726 }
727 packet_size /= CHAR_BIT;
728 } else {
729 packet_size = subbuf_size;
730 }
731 } else {
732 uint64_t patch_size;
733
734 /*
735 * Find where to patch the sub-buffer header with actual
736 * readable data len and packet len, derived from seq
737 * cc. Patch it in our in-memory copy.
738 */
739 patch_size = committed * CHAR_BIT;
740 if (layout->reverse_byte_order) {
741 patch_size = __bswap_64(patch_size);
742 }
743 if (layout->length.content_size) {
744 memcpy(subbuf_ptr + layout->offset.content_size,
745 &patch_size, layout->length.content_size);
746 }
747 if (layout->length.packet_size) {
748 memcpy(subbuf_ptr + layout->offset.packet_size,
749 &patch_size, layout->length.packet_size);
750 }
751 packet_size = committed;
752 }
753
754 /*
755 * Copy packet into fd_dest.
756 */
757 writelen = lttng_write(fd_dest, subbuf_ptr, packet_size);
758 if (writelen < packet_size) {
759 PERROR("Error writing to output file");
760 return -1;
761 }
762 DBG("Copied %" PRIu64 " bytes of data", packet_size);
763 return 0;
764
765nodata:
766 return -ENODATA;
767}
768
769static
770int copy_crash_data(const struct lttng_crash_layout *layout, int fd_dest,
771 int fd_src)
772{
773 char *buf;
774 int ret = 0, has_data = 0;
775 struct stat statbuf;
776 size_t src_file_len;
777 uint64_t prod_offset, consumed_offset;
778 uint64_t offset, subbuf_size;
779 ssize_t readlen;
780
781 ret = fstat(fd_src, &statbuf);
782 if (ret) {
783 return ret;
784 }
785 src_file_len = layout->mmap_length;
786 buf = zmalloc(src_file_len);
787 if (!buf) {
788 return -1;
789 }
790 readlen = lttng_read(fd_src, buf, src_file_len);
791 if (readlen < 0) {
792 PERROR("Error reading input file");
309fc9bf
MD
793 ret = -1;
794 goto end;
d7ba1388
MD
795 }
796
797 prod_offset = crash_get_field(layout, buf, prod_offset);
798 DBG("prod_offset: 0x%" PRIx64, prod_offset);
799 consumed_offset = crash_get_field(layout, buf, consumed_offset);
800 DBG("consumed_offset: 0x%" PRIx64, consumed_offset);
801 subbuf_size = layout->subbuf_size;
802
803 for (offset = consumed_offset; offset < prod_offset;
804 offset += subbuf_size) {
805 ret = copy_crash_subbuf(layout, fd_dest, buf, offset);
806 if (!ret) {
807 has_data = 1;
808 }
809 if (ret) {
810 goto end;
811 }
812 }
813end:
814 free(buf);
815 if (ret && ret != -ENODATA) {
816 return ret;
817 }
818 if (has_data) {
819 return 0;
820 } else {
821 return -ENODATA;
822 }
823}
824
825static
826int extract_file(int output_dir_fd, const char *output_file,
827 int input_dir_fd, const char *input_file)
828{
829 int fd_dest, fd_src, ret = 0, closeret;
830 struct lttng_crash_layout layout;
831
832 layout.reverse_byte_order = 0; /* For reading magic number */
833
834 DBG("Extract file '%s'", input_file);
835 fd_src = openat(input_dir_fd, input_file, O_RDONLY);
836 if (fd_src < 0) {
837 PERROR("Error opening '%s' for reading",
838 input_file);
839 ret = -1;
840 goto end;
841 }
842
843 /* Query the crash ABI layout */
844 ret = get_crash_layout(&layout, fd_src);
845 if (ret) {
846 goto close_src;
847 }
848
849 fd_dest = openat(output_dir_fd, output_file,
850 O_RDWR | O_CREAT | O_EXCL,
851 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
852 if (fd_dest < 0) {
853 PERROR("Error opening '%s' for writing",
854 output_file);
855 ret = -1;
856 goto close_src;
857 }
858
859 ret = copy_crash_data(&layout, fd_dest, fd_src);
860 if (ret) {
861 goto close_dest;
862 }
863
864close_dest:
865 closeret = close(fd_dest);
866 if (closeret) {
867 PERROR("close");
868 }
869 if (ret == -ENODATA) {
870 closeret = unlinkat(output_dir_fd, output_file, 0);
871 if (closeret) {
872 PERROR("unlinkat");
873 }
874 }
875close_src:
876 closeret = close(fd_src);
877 if (closeret) {
878 PERROR("close");
879 }
880end:
881 return ret;
882}
883
884static
885int extract_all_files(const char *output_path,
886 const char *input_path)
887{
888 DIR *input_dir, *output_dir;
889 int input_dir_fd, output_dir_fd, ret = 0, closeret;
890 struct dirent *entry; /* input */
891
892 /* Open input directory */
893 input_dir = opendir(input_path);
894 if (!input_dir) {
895 PERROR("Cannot open '%s' path", input_path);
896 return -1;
897 }
898 input_dir_fd = dirfd(input_dir);
899 if (input_dir_fd < 0) {
900 PERROR("dirfd");
901 return -1;
902 }
903
904 /* Open output directory */
905 output_dir = opendir(output_path);
906 if (!output_dir) {
907 PERROR("Cannot open '%s' path", output_path);
908 return -1;
909 }
910 output_dir_fd = dirfd(output_dir);
911 if (output_dir_fd < 0) {
912 PERROR("dirfd");
913 return -1;
914 }
915
916 while ((entry = readdir(input_dir))) {
917 if (!strcmp(entry->d_name, ".")
918 || !strcmp(entry->d_name, ".."))
919 continue;
920 ret = extract_file(output_dir_fd, entry->d_name,
921 input_dir_fd, entry->d_name);
922 if (ret == -ENODATA) {
923 DBG("No data in file '%s', skipping", entry->d_name);
924 ret = 0;
925 continue;
926 } else if (ret < 0) {
927 break;
928 } else if (ret > 0) {
929 DBG("Skipping file '%s'", entry->d_name);
930 ret = 0;
931 continue;
932 }
933 }
934 closeret = closedir(output_dir);
935 if (closeret) {
936 PERROR("closedir");
937 }
938 closeret = closedir(input_dir);
939 if (closeret) {
940 PERROR("closedir");
941 }
942 return ret;
943}
944
945static
946int extract_one_trace(const char *output_path,
947 const char *input_path)
948{
949 char dest[PATH_MAX], src[PATH_MAX];
950 int ret;
951
952 DBG("Extract crash trace '%s' into '%s'", input_path, output_path);
953
954 /* Copy metadata */
955 strncpy(dest, output_path, PATH_MAX);
956 dest[PATH_MAX - 1] = '\0';
957 strncat(dest, "/metadata", PATH_MAX - strlen(dest) - 1);
958
959 strncpy(src, input_path, PATH_MAX);
960 src[PATH_MAX - 1] = '\0';
961 strncat(src, "/metadata", PATH_MAX - strlen(dest) - 1);
962
963 ret = copy_file(dest, src);
964 if (ret) {
965 return ret;
966 }
967
968 /* Extract each other file that has expected header */
969 return extract_all_files(output_path, input_path);
970}
971
972static
a424227e
MD
973int extract_trace_recursive(const char *output_path,
974 const char *input_path)
d7ba1388 975{
a424227e
MD
976 DIR *dir;
977 int dir_fd, ret = 0, closeret;
978 struct dirent *entry;
d7ba1388
MD
979 int has_warning = 0;
980
a424227e
MD
981 /* Open directory */
982 dir = opendir(input_path);
983 if (!dir) {
984 PERROR("Cannot open '%s' path", input_path);
985 return -1;
986 }
987 dir_fd = dirfd(dir);
988 if (dir_fd < 0) {
989 PERROR("dirfd");
d7ba1388
MD
990 return -1;
991 }
992
a424227e
MD
993 while ((entry = readdir(dir))) {
994 if (!strcmp(entry->d_name, ".")
995 || !strcmp(entry->d_name, "..")) {
996 continue;
997 }
998 switch (entry->d_type) {
999 case DT_DIR:
1000 {
1001 char output_subpath[PATH_MAX];
1002 char input_subpath[PATH_MAX];
1003
1004 strncpy(output_subpath, output_path,
1005 sizeof(output_subpath));
1006 output_subpath[sizeof(output_subpath) - 1] = '\0';
1007 strncat(output_subpath, "/",
1008 sizeof(output_subpath) - strlen(output_subpath) - 1);
1009 strncat(output_subpath, entry->d_name,
1010 sizeof(output_subpath) - strlen(output_subpath) - 1);
1011
1012 ret = mkdir(output_subpath, S_IRWXU | S_IRWXG);
1013 if (ret) {
1014 PERROR("mkdir");
1015 has_warning = 1;
1016 goto end;
1017 }
1018
1019 strncpy(input_subpath, input_path,
1020 sizeof(input_subpath));
1021 input_subpath[sizeof(input_subpath) - 1] = '\0';
1022 strncat(input_subpath, "/",
1023 sizeof(input_subpath) - strlen(input_subpath) - 1);
1024 strncat(input_subpath, entry->d_name,
1025 sizeof(input_subpath) - strlen(input_subpath) - 1);
1026
1027 ret = extract_trace_recursive(output_subpath,
1028 input_subpath);
29786dfa
JG
1029 if (ret) {
1030 has_warning = 1;
1031 }
a424227e
MD
1032 break;
1033 }
1034 case DT_REG:
93c4b583 1035 case DT_LNK:
a424227e
MD
1036 if (!strcmp(entry->d_name, "metadata")) {
1037 ret = extract_one_trace(output_path,
1038 input_path);
1039 if (ret) {
1040 WARN("Error extracting trace '%s', continuing anyway.",
1041 input_path);
1042 has_warning = 1;
1043 }
1044 }
1045 /* Ignore other files */
1046 break;
1047 default:
d7ba1388 1048 has_warning = 1;
a424227e 1049 goto end;
d7ba1388
MD
1050 }
1051 }
a424227e
MD
1052end:
1053 closeret = closedir(dir);
1054 if (closeret) {
1055 PERROR("closedir");
1056 }
d7ba1388
MD
1057 return has_warning;
1058}
1059
1060static
afe4fd7c 1061int delete_dir_recursive(const char *path)
d7ba1388 1062{
afe4fd7c
JR
1063 DIR *dir;
1064 int dir_fd, ret = 0, closeret;
d7ba1388
MD
1065 struct dirent *entry;
1066
1067 /* Open trace directory */
afe4fd7c
JR
1068 dir = opendir(path);
1069 if (!dir) {
1070 PERROR("Cannot open '%s' path", path);
920a187e
JG
1071 ret = -errno;
1072 goto end;
d7ba1388 1073 }
afe4fd7c
JR
1074 dir_fd = dirfd(dir);
1075 if (dir_fd < 0) {
d7ba1388 1076 PERROR("dirfd");
920a187e
JG
1077 ret = -errno;
1078 goto end;
d7ba1388
MD
1079 }
1080
afe4fd7c 1081 while ((entry = readdir(dir))) {
d7ba1388 1082 if (!strcmp(entry->d_name, ".")
a424227e 1083 || !strcmp(entry->d_name, "..")) {
d7ba1388 1084 continue;
a424227e 1085 }
d7ba1388
MD
1086 switch (entry->d_type) {
1087 case DT_DIR:
afe4fd7c
JR
1088 {
1089 char *subpath = zmalloc(PATH_MAX);
1090
1091 if (!subpath) {
1092 PERROR("zmalloc path");
1093 ret = -1;
1094 goto end;
1095 }
1096 strncpy(subpath, path, PATH_MAX);
1097 subpath[PATH_MAX - 1] = '\0';
1098 strncat(subpath, "/",
1099 PATH_MAX - strlen(subpath) - 1);
1100 strncat(subpath, entry->d_name,
1101 PATH_MAX - strlen(subpath) - 1);
1102
1103 ret = delete_dir_recursive(subpath);
1104 free(subpath);
1105 if (ret) {
1106 /* Error occured, abort traversal. */
1107 goto end;
1108 }
d7ba1388 1109 break;
afe4fd7c 1110 }
d7ba1388 1111 case DT_REG:
afe4fd7c
JR
1112 ret = unlinkat(dir_fd, entry->d_name, 0);
1113 if (ret) {
1114 PERROR("Unlinking '%s'", entry->d_name);
1115 goto end;
1116 }
d7ba1388
MD
1117 break;
1118 default:
1119 ret = -EINVAL;
1120 goto end;
1121 }
1122 }
1123end:
afe4fd7c
JR
1124 if (!ret) {
1125 ret = rmdir(path);
1126 if (ret) {
1127 PERROR("rmdir '%s'", path);
1128 }
1129 }
1130 closeret = closedir(dir);
d7ba1388
MD
1131 if (closeret) {
1132 PERROR("closedir");
1133 }
d7ba1388
MD
1134 return ret;
1135}
1136
d7ba1388
MD
1137static
1138int view_trace(const char *viewer_path, const char *trace_path)
1139{
1140 pid_t pid;
1141
1142 pid = fork();
1143 if (pid < 0) {
1144 /* Error */
1145 PERROR("fork");
1146 return -1;
1147 } else if (pid > 0) {
1148 /* Parent */
1149 int status;
1150
1151 pid = waitpid(pid, &status, 0);
1152 if (pid < 0 || !WIFEXITED(status)) {
1153 return -1;
1154 }
1155 } else {
1156 /* Child */
1157 int ret;
1158
1159 ret = execlp(viewer_path, viewer_path,
1160 trace_path, (char *) NULL);
1161 if (ret) {
1162 PERROR("execlp");
1163 exit(EXIT_FAILURE);
1164 }
1165 exit(EXIT_SUCCESS); /* Never reached */
1166 }
1167 return 0;
1168}
1169
1170/*
1171 * main
1172 */
1173int main(int argc, char *argv[])
1174{
aa25d686
JG
1175 int ret;
1176 bool has_warning = false;
d7ba1388
MD
1177 const char *output_path = NULL;
1178 char tmppath[] = "/tmp/lttng-crash-XXXXXX";
1179
1180 progname = argv[0] ? argv[0] : "lttng-crash";
1181
1182 ret = parse_args(argc, argv);
1183 if (ret > 0) {
aa25d686 1184 goto end;
d7ba1388 1185 } else if (ret < 0) {
aa25d686
JG
1186 has_warning = true;
1187 goto end;
d7ba1388
MD
1188 }
1189
1190 if (opt_output_path) {
1191 output_path = opt_output_path;
1192 ret = mkdir(output_path, S_IRWXU | S_IRWXG);
1193 if (ret) {
1194 PERROR("mkdir");
aa25d686
JG
1195 has_warning = true;
1196 goto end;
d7ba1388
MD
1197 }
1198 } else {
1199 output_path = mkdtemp(tmppath);
1200 if (!output_path) {
1201 PERROR("mkdtemp");
aa25d686
JG
1202 has_warning = true;
1203 goto end;
d7ba1388
MD
1204 }
1205 }
1206
a424227e 1207 ret = extract_trace_recursive(output_path, input_path);
d7ba1388 1208 if (ret < 0) {
aa25d686
JG
1209 has_warning = true;
1210 goto end;
d7ba1388 1211 } else if (ret > 0) {
aa25d686
JG
1212 /* extract_trace_recursive reported a warning. */
1213 has_warning = true;
d7ba1388
MD
1214 }
1215 if (!opt_output_path) {
1216 /* View trace */
1217 ret = view_trace(opt_viewer_path, output_path);
aa25d686
JG
1218 if (ret) {
1219 has_warning = true;
1220 }
d7ba1388 1221 /* unlink temporary trace */
afe4fd7c 1222 ret = delete_dir_recursive(output_path);
aa25d686
JG
1223 if (ret) {
1224 has_warning = true;
1225 }
d7ba1388 1226 }
aa25d686
JG
1227end:
1228 exit(has_warning ? EXIT_FAILURE : EXIT_SUCCESS);
d7ba1388 1229}
This page took 0.120011 seconds and 4 git commands to generate.