Fix: lttng-snapshot: use after free of max size argument
[lttng-tools.git] / src / bin / lttng-crash / lttng-crash.cpp
CommitLineData
d7ba1388 1/*
21cf9b6b 2 * Copyright (C) 2011 EfficiOS Inc.
d7ba1388
MD
3 * Copyright (C) 2014 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
4 *
ab5be9fa 5 * SPDX-License-Identifier: GPL-2.0-only
d7ba1388 6 *
d7ba1388
MD
7 */
8
d7ba1388
MD
9#include <getopt.h>
10#include <signal.h>
11#include <stdio.h>
12#include <stdlib.h>
13#include <string.h>
14#include <sys/stat.h>
15#include <sys/types.h>
16#include <sys/stat.h>
17#include <sys/mman.h>
18#include <fcntl.h>
19#include <sys/wait.h>
20#include <unistd.h>
d7ba1388
MD
21#include <ctype.h>
22#include <dirent.h>
c9e313bc 23#include <common/compat/endian.hpp>
d7ba1388 24#include <inttypes.h>
aa25d686 25#include <stdbool.h>
d7ba1388 26
c9e313bc 27#include <version.hpp>
d7ba1388 28#include <lttng/lttng.h>
c9e313bc
SM
29#include <common/common.hpp>
30#include <common/spawn-viewer.hpp>
31#include <common/utils.hpp>
d7ba1388 32
d7ba1388
MD
33#define COPY_BUFLEN 4096
34#define RB_CRASH_DUMP_ABI_LEN 32
35
36#define RB_CRASH_DUMP_ABI_MAGIC_LEN 16
37
38/*
39 * The 128-bit magic number is xor'd in the process data so it does not
40 * cause a false positive when searching for buffers by scanning memory.
41 * The actual magic number is:
42 * 0x17, 0x7B, 0xF1, 0x77, 0xBF, 0x17, 0x7B, 0xF1,
43 * 0x77, 0xBF, 0x17, 0x7B, 0xF1, 0x77, 0xBF, 0x17,
44 */
45#define RB_CRASH_DUMP_ABI_MAGIC_XOR \
46 { \
47 0x17 ^ 0xFF, 0x7B ^ 0xFF, 0xF1 ^ 0xFF, 0x77 ^ 0xFF, \
48 0xBF ^ 0xFF, 0x17 ^ 0xFF, 0x7B ^ 0xFF, 0xF1 ^ 0xFF, \
49 0x77 ^ 0xFF, 0xBF ^ 0xFF, 0x17 ^ 0xFF, 0x7B ^ 0xFF, \
50 0xF1 ^ 0xFF, 0x77 ^ 0xFF, 0xBF ^ 0xFF, 0x17 ^ 0xFF, \
51 }
52
4fc83d94
PP
53static const char *help_msg =
54#ifdef LTTNG_EMBED_HELP
55#include <lttng-crash.1.h>
56#else
57NULL
58#endif
59;
60
d7ba1388
MD
61/*
62 * Non-static to ensure the compiler does not optimize away the xor.
63 */
64uint8_t lttng_crash_expected_magic_xor[] = RB_CRASH_DUMP_ABI_MAGIC_XOR;
65
66#define RB_CRASH_ENDIAN 0x1234
67#define RB_CRASH_ENDIAN_REVERSE 0x3412
68
69enum lttng_crash_type {
70 LTTNG_CRASH_TYPE_UST = 0,
71 LTTNG_CRASH_TYPE_KERNEL = 1,
72};
73
74/* LTTng ring buffer defines (copied) */
75
76#define HALF_ULONG_BITS(wl) (((wl) * CHAR_BIT) >> 1)
77
78#define SB_ID_OFFSET_SHIFT(wl) (HALF_ULONG_BITS(wl) + 1)
79#define SB_ID_OFFSET_COUNT(wl) (1UL << SB_ID_OFFSET_SHIFT(wl))
80#define SB_ID_OFFSET_MASK(wl) (~(SB_ID_OFFSET_COUNT(wl) - 1))
81/*
82 * Lowest bit of top word half belongs to noref. Used only for overwrite mode.
83 */
84#define SB_ID_NOREF_SHIFT(wl) (SB_ID_OFFSET_SHIFT(wl) - 1)
85#define SB_ID_NOREF_COUNT(wl) (1UL << SB_ID_NOREF_SHIFT(wl))
86#define SB_ID_NOREF_MASK(wl) SB_ID_NOREF_COUNT(wl)
87/*
88 * In overwrite mode: lowest half of word is used for index.
89 * Limit of 2^16 subbuffers per buffer on 32-bit, 2^32 on 64-bit.
90 * In producer-consumer mode: whole word used for index.
91 */
92#define SB_ID_INDEX_SHIFT(wl) 0
93#define SB_ID_INDEX_COUNT(wl) (1UL << SB_ID_INDEX_SHIFT(wl))
94#define SB_ID_INDEX_MASK(wl) (SB_ID_NOREF_COUNT(wl) - 1)
95
96enum rb_modes {
97 RING_BUFFER_OVERWRITE = 0, /* Overwrite when buffer full */
98 RING_BUFFER_DISCARD = 1, /* Discard when buffer full */
99};
100
f1494934 101namespace {
d7ba1388
MD
102struct crash_abi_unknown {
103 uint8_t magic[RB_CRASH_DUMP_ABI_MAGIC_LEN];
8726a045 104 uint64_t mmap_length; /* Overall length of crash record */
d7ba1388
MD
105 uint16_t endian; /*
106 * { 0x12, 0x34 }: big endian
107 * { 0x34, 0x12 }: little endian
108 */
109 uint16_t major; /* Major number. */
110 uint16_t minor; /* Minor number. */
111 uint8_t word_size; /* Word size (bytes). */
112 uint8_t layout_type; /* enum lttng_crash_layout */
113} __attribute__((packed));
114
115struct crash_abi_0_0 {
116 struct crash_abi_unknown parent;
117
118 struct {
119 uint32_t prod_offset;
120 uint32_t consumed_offset;
121 uint32_t commit_hot_array;
122 uint32_t commit_hot_seq;
123 uint32_t buf_wsb_array;
124 uint32_t buf_wsb_id;
125 uint32_t sb_array;
126 uint32_t sb_array_shmp_offset;
127 uint32_t sb_backend_p_offset;
128 uint32_t content_size;
129 uint32_t packet_size;
130 } __attribute__((packed)) offset;
131 struct {
132 uint8_t prod_offset;
133 uint8_t consumed_offset;
134 uint8_t commit_hot_seq;
135 uint8_t buf_wsb_id;
136 uint8_t sb_array_shmp_offset;
137 uint8_t sb_backend_p_offset;
138 uint8_t content_size;
139 uint8_t packet_size;
140 } __attribute__((packed)) length;
141 struct {
142 uint32_t commit_hot_array;
143 uint32_t buf_wsb_array;
144 uint32_t sb_array;
145 } __attribute__((packed)) stride;
146
147 uint64_t buf_size; /* Size of the buffer */
148 uint64_t subbuf_size; /* Sub-buffer size */
149 uint64_t num_subbuf; /* Number of sub-buffers for writer */
150 uint32_t mode; /* Buffer mode: 0: overwrite, 1: discard */
151} __attribute__((packed));
152
153struct lttng_crash_layout {
154 struct {
155 int prod_offset, consumed_offset,
156 commit_hot_array, commit_hot_seq,
157 buf_wsb_array, buf_wsb_id,
158 sb_array, sb_array_shmp_offset,
159 sb_backend_p_offset, content_size,
160 packet_size;
161 } offset;
162 struct {
163 int prod_offset, consumed_offset,
164 commit_hot_seq, buf_wsb_id,
165 sb_array_shmp_offset, sb_backend_p_offset,
166 content_size, packet_size;
167 } length;
168 struct {
169 int commit_hot_array, buf_wsb_array, sb_array;
170 } stride;
171
172 int reverse_byte_order;
173 int word_size;
174
175 uint64_t mmap_length; /* Length of crash record */
176 uint64_t buf_size; /* Size of the buffer */
177 uint64_t subbuf_size; /* Sub-buffer size */
178 uint64_t num_subbuf; /* Number of sub-buffers for writer */
179 uint32_t mode; /* Buffer mode: 0: overwrite, 1: discard */
180};
f1494934 181} /* namespace */
d7ba1388
MD
182
183/* Variables */
b53d4e59
SM
184static const char *progname;
185static char *opt_viewer_path = NULL;
186static char *opt_output_path = NULL;
d7ba1388 187
40b4fee7 188static char *the_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
6ef14df5 207static void usage(void)
d7ba1388 208{
4fc83d94 209 int ret = utils_show_help(1, "lttng-crash", help_msg);
6ef14df5
PP
210
211 if (ret) {
4fc83d94 212 ERR("Cannot show --help for `lttng-crash`");
6ef14df5
PP
213 perror("exec");
214 exit(EXIT_FAILURE);
215 }
d7ba1388
MD
216}
217
218static void version(FILE *ofp)
219{
220 fprintf(ofp, "%s (LTTng Crash Trace Viewer) " VERSION " - " VERSION_NAME
6f4a662d 221 "%s%s\n",
d7ba1388 222 progname,
a3bc3918
JR
223 GIT_VERSION[0] == '\0' ? "" : " - " GIT_VERSION,
224 EXTRA_VERSION_NAME[0] == '\0' ? "" : " - " EXTRA_VERSION_NAME);
d7ba1388
MD
225}
226
227/*
228 * list_options
229 *
230 * List options line by line. This is mostly for bash auto completion and to
231 * avoid difficult parsing.
232 */
233static void list_options(FILE *ofp)
234{
235 int i = 0;
236 struct option *option = NULL;
237
238 option = &long_options[i];
239 while (option->name != NULL) {
240 fprintf(ofp, "--%s\n", option->name);
241
242 if (isprint(option->val)) {
243 fprintf(ofp, "-%c\n", option->val);
244 }
245
246 i++;
247 option = &long_options[i];
248 }
249}
250
251/*
252 * Parse command line arguments.
253 *
254 * Return 0 if OK, else -1
255 */
256static int parse_args(int argc, char **argv)
257{
258 int opt, ret = 0;
259
260 if (argc < 2) {
6ef14df5 261 usage();
d7ba1388
MD
262 exit(EXIT_FAILURE);
263 }
264
d07f3d99 265 while ((opt = getopt_long(argc, argv, "+Vhve:x:", long_options, NULL)) != -1) {
d7ba1388
MD
266 switch (opt) {
267 case 'V':
268 version(stdout);
269 ret = 1;
270 goto end;
271 case 'h':
6ef14df5 272 usage();
d7ba1388
MD
273 ret = 1;
274 goto end;
275 case 'v':
276 /* There is only 3 possible level of verbosity. (-vvv) */
277 if (lttng_opt_verbose < 3) {
278 lttng_opt_verbose += 1;
279 }
280 break;
281 case 'e':
9030e9a9 282 free(opt_viewer_path);
d7ba1388
MD
283 opt_viewer_path = strdup(optarg);
284 break;
285 case 'x':
9030e9a9 286 free(opt_output_path);
d7ba1388
MD
287 opt_output_path = strdup(optarg);
288 break;
289 case OPT_DUMP_OPTIONS:
290 list_options(stdout);
291 ret = 1;
292 goto end;
293 default:
6ef14df5 294 ERR("Unknown command-line option");
d7ba1388
MD
295 goto error;
296 }
297 }
298
a424227e 299 /* No leftovers, or more than one input path, print usage and quit */
6ef14df5
PP
300 if (argc - optind != 1) {
301 ERR("Command-line error: Specify exactly one input path");
d7ba1388
MD
302 goto error;
303 }
304
40b4fee7 305 the_input_path = argv[optind];
d7ba1388
MD
306end:
307 return ret;
308
309error:
310 return -1;
311}
312
313static
314int copy_file(const char *file_dest, const char *file_src)
315{
8726a045 316 int fd_src = -1, fd_dest = -1;
d7ba1388
MD
317 ssize_t readlen, writelen;
318 char buf[COPY_BUFLEN];
8726a045 319 int ret;
d7ba1388
MD
320
321 DBG("Copy metadata file '%s' into '%s'", file_src, file_dest);
322
323 fd_src = open(file_src, O_RDONLY);
324 if (fd_src < 0) {
325 PERROR("Error opening %s for reading", file_src);
8726a045
JR
326 ret = -errno;
327 goto error;
d7ba1388
MD
328 }
329 fd_dest = open(file_dest, O_RDWR | O_CREAT | O_EXCL,
330 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
331 if (fd_dest < 0) {
332 PERROR("Error opening %s for writing", file_dest);
8726a045
JR
333 ret = -errno;
334 goto error;
d7ba1388
MD
335 }
336
337 for (;;) {
338 readlen = lttng_read(fd_src, buf, COPY_BUFLEN);
339 if (readlen < 0) {
340 PERROR("Error reading input file");
8726a045
JR
341 ret = -1;
342 goto error;
d7ba1388
MD
343 }
344 if (!readlen) {
345 break;
346 }
347 writelen = lttng_write(fd_dest, buf, readlen);
348 if (writelen < readlen) {
349 PERROR("Error writing to output file");
8726a045
JR
350 ret = -1;
351 goto error;
352 }
353 }
354
355 ret = 0;
356error:
357 if (fd_src >= 0) {
358 if (close(fd_src) < 0) {
359 PERROR("Error closing %s", file_src);
360 }
361 }
362
363 if (fd_dest >= 0) {
364 if (close(fd_dest) < 0) {
365 PERROR("Error closing %s", file_dest);
d7ba1388
MD
366 }
367 }
8726a045 368 return ret;
d7ba1388
MD
369}
370
371static
372uint64_t _crash_get_field(const struct lttng_crash_layout *layout,
373 const char *ptr, size_t size)
374{
375 switch (size) {
376 case 1: return *(uint8_t *) ptr;
377 case 2: if (layout->reverse_byte_order) {
4ff128af 378 return bswap_16(*(uint16_t *) ptr);
d7ba1388
MD
379 } else {
380 return *(uint16_t *) ptr;
381
382 }
383 case 4: if (layout->reverse_byte_order) {
4ff128af 384 return bswap_32(*(uint32_t *) ptr);
d7ba1388
MD
385 } else {
386 return *(uint32_t *) ptr;
387
388 }
389 case 8: if (layout->reverse_byte_order) {
4ff128af 390 return bswap_64(*(uint64_t *) ptr);
d7ba1388
MD
391 } else {
392 return *(uint64_t *) ptr;
393 }
394 default:
395 abort();
396 return -1;
397 }
398
399}
400
401#define crash_get_field(layout, map, name) \
402 _crash_get_field(layout, (map) + (layout)->offset.name, \
403 layout->length.name)
404
405#define crash_get_array_field(layout, map, array_name, idx, field_name) \
406 _crash_get_field(layout, \
407 (map) + (layout)->offset.array_name \
408 + (idx * (layout)->stride.array_name) \
409 + (layout)->offset.field_name, \
410 (layout)->length.field_name)
411
412#define crash_get_hdr_raw_field(layout, hdr, name) ((hdr)->name)
413
414#define crash_get_hdr_field(layout, hdr, name) \
415 _crash_get_field(layout, (const char *) &(hdr)->name, \
416 sizeof((hdr)->name))
417
418#define crash_get_layout(layout, hdr, name) \
419 do { \
420 (layout)->name = crash_get_hdr_field(layout, hdr, \
421 name); \
422 DBG("layout.%s = %" PRIu64, #name, \
423 (uint64_t) (layout)->name); \
424 } while (0)
425
426static
427int get_crash_layout_0_0(struct lttng_crash_layout *layout,
428 char *map)
429{
430 const struct crash_abi_0_0 *abi = (const struct crash_abi_0_0 *) map;
431
432 crash_get_layout(layout, abi, offset.prod_offset);
433 crash_get_layout(layout, abi, offset.consumed_offset);
434 crash_get_layout(layout, abi, offset.commit_hot_array);
435 crash_get_layout(layout, abi, offset.commit_hot_seq);
436 crash_get_layout(layout, abi, offset.buf_wsb_array);
437 crash_get_layout(layout, abi, offset.buf_wsb_id);
438 crash_get_layout(layout, abi, offset.sb_array);
439 crash_get_layout(layout, abi, offset.sb_array_shmp_offset);
440 crash_get_layout(layout, abi, offset.sb_backend_p_offset);
441 crash_get_layout(layout, abi, offset.content_size);
442 crash_get_layout(layout, abi, offset.packet_size);
443
444 crash_get_layout(layout, abi, length.prod_offset);
445 crash_get_layout(layout, abi, length.consumed_offset);
446 crash_get_layout(layout, abi, length.commit_hot_seq);
447 crash_get_layout(layout, abi, length.buf_wsb_id);
448 crash_get_layout(layout, abi, length.sb_array_shmp_offset);
449 crash_get_layout(layout, abi, length.sb_backend_p_offset);
450 crash_get_layout(layout, abi, length.content_size);
451 crash_get_layout(layout, abi, length.packet_size);
452
453 crash_get_layout(layout, abi, stride.commit_hot_array);
454 crash_get_layout(layout, abi, stride.buf_wsb_array);
455 crash_get_layout(layout, abi, stride.sb_array);
456
457 crash_get_layout(layout, abi, buf_size);
458 crash_get_layout(layout, abi, subbuf_size);
459 crash_get_layout(layout, abi, num_subbuf);
460 crash_get_layout(layout, abi, mode);
461
462 return 0;
463}
464
465static
466void print_dbg_magic(const uint8_t *magic)
467{
468 DBG("magic: 0x%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X",
469 magic[0], magic[1], magic[2], magic[3],
470 magic[4], magic[5], magic[6], magic[7],
471 magic[8], magic[9], magic[10], magic[11],
472 magic[12], magic[13], magic[14], magic[15]);
473}
474
475static
476int check_magic(const uint8_t *magic)
477{
478 int i;
479
480 for (i = 0; i < RB_CRASH_DUMP_ABI_MAGIC_LEN; i++) {
481 if ((magic[i] ^ 0xFF) != lttng_crash_expected_magic_xor[i]) {
482 return -1;
483 }
484 }
485 return 0;
486}
487
488static
e6c6e235
MD
489int get_crash_layout(struct lttng_crash_layout *layout, int fd,
490 const char *input_file)
d7ba1388
MD
491{
492 char *map;
493 int ret = 0, unmapret;
494 const uint8_t *magic;
495 uint64_t mmap_length;
496 uint16_t major, minor;
497 uint8_t word_size;
498 const struct crash_abi_unknown *abi;
499 uint16_t endian;
500 enum lttng_crash_type layout_type;
e6c6e235 501 struct stat stat;
d7ba1388 502
e6c6e235
MD
503 ret = fstat(fd, &stat);
504 if (ret < 0) {
505 PERROR("Failed to fstat '%s'", input_file);
506 return -1;
507 }
508 if (stat.st_size < RB_CRASH_DUMP_ABI_LEN) {
509 ERR("File '%s' truncated: file length of %" PRIi64
510 " bytes does not meet the minimal expected "
511 "length of %d bytes",
512 input_file, (int64_t) stat.st_size,
513 RB_CRASH_DUMP_ABI_LEN);
514 return -1;
515 }
aa4e4813 516 map = (char *) mmap(NULL, RB_CRASH_DUMP_ABI_LEN, PROT_READ, MAP_PRIVATE,
d7ba1388
MD
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) {
4ff128af 725 packet_size = bswap_64(packet_size);
d7ba1388
MD
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) {
4ff128af 741 patch_size = bswap_64(patch_size);
d7ba1388
MD
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;
64803277 786 buf = calloc<char>(src_file_len);
d7ba1388
MD
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 */
e6c6e235 844 ret = get_crash_layout(&layout, fd_src, input_file);
d7ba1388
MD
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;
88ae485a 979 size_t path_len;
d7ba1388
MD
980 int has_warning = 0;
981
a424227e
MD
982 /* Open directory */
983 dir = opendir(input_path);
984 if (!dir) {
985 PERROR("Cannot open '%s' path", input_path);
986 return -1;
987 }
88ae485a
JR
988
989 path_len = strlen(input_path);
990
a424227e
MD
991 dir_fd = dirfd(dir);
992 if (dir_fd < 0) {
993 PERROR("dirfd");
d7ba1388
MD
994 return -1;
995 }
996
a424227e 997 while ((entry = readdir(dir))) {
88ae485a
JR
998 struct stat st;
999 size_t name_len;
1000 char filename[PATH_MAX];
1001
a424227e
MD
1002 if (!strcmp(entry->d_name, ".")
1003 || !strcmp(entry->d_name, "..")) {
1004 continue;
1005 }
88ae485a
JR
1006
1007 name_len = strlen(entry->d_name);
1008 if (path_len + name_len + 2 > sizeof(filename)) {
1009 ERR("Failed to remove file: path name too long (%s/%s)",
1010 input_path, entry->d_name);
1011 continue;
1012 }
1013
1014 if (snprintf(filename, sizeof(filename), "%s/%s",
1015 input_path, entry->d_name) < 0) {
1016 ERR("Failed to format path.");
1017 continue;
1018 }
1019
1020 if (stat(filename, &st)) {
1021 PERROR("stat");
1022 continue;
1023 }
1024
1025 if (S_ISDIR(st.st_mode)) {
a424227e
MD
1026 char output_subpath[PATH_MAX];
1027 char input_subpath[PATH_MAX];
1028
1029 strncpy(output_subpath, output_path,
1030 sizeof(output_subpath));
1031 output_subpath[sizeof(output_subpath) - 1] = '\0';
1032 strncat(output_subpath, "/",
1033 sizeof(output_subpath) - strlen(output_subpath) - 1);
1034 strncat(output_subpath, entry->d_name,
1035 sizeof(output_subpath) - strlen(output_subpath) - 1);
1036
1037 ret = mkdir(output_subpath, S_IRWXU | S_IRWXG);
1038 if (ret) {
1039 PERROR("mkdir");
1040 has_warning = 1;
1041 goto end;
1042 }
1043
1044 strncpy(input_subpath, input_path,
1045 sizeof(input_subpath));
1046 input_subpath[sizeof(input_subpath) - 1] = '\0';
1047 strncat(input_subpath, "/",
1048 sizeof(input_subpath) - strlen(input_subpath) - 1);
1049 strncat(input_subpath, entry->d_name,
1050 sizeof(input_subpath) - strlen(input_subpath) - 1);
1051
1052 ret = extract_trace_recursive(output_subpath,
1053 input_subpath);
29786dfa
JG
1054 if (ret) {
1055 has_warning = 1;
1056 }
88ae485a 1057 } else if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
a424227e
MD
1058 if (!strcmp(entry->d_name, "metadata")) {
1059 ret = extract_one_trace(output_path,
1060 input_path);
1061 if (ret) {
1062 WARN("Error extracting trace '%s', continuing anyway.",
1063 input_path);
1064 has_warning = 1;
1065 }
1066 }
88ae485a 1067 } else {
d7ba1388 1068 has_warning = 1;
a424227e 1069 goto end;
d7ba1388
MD
1070 }
1071 }
a424227e
MD
1072end:
1073 closeret = closedir(dir);
1074 if (closeret) {
1075 PERROR("closedir");
1076 }
d7ba1388
MD
1077 return has_warning;
1078}
1079
1080static
afe4fd7c 1081int delete_dir_recursive(const char *path)
d7ba1388 1082{
afe4fd7c
JR
1083 DIR *dir;
1084 int dir_fd, ret = 0, closeret;
88ae485a 1085 size_t path_len;
d7ba1388
MD
1086 struct dirent *entry;
1087
1088 /* Open trace directory */
afe4fd7c
JR
1089 dir = opendir(path);
1090 if (!dir) {
1091 PERROR("Cannot open '%s' path", path);
920a187e 1092 ret = -errno;
ef6fc488 1093 goto end_no_closedir;
d7ba1388 1094 }
88ae485a
JR
1095
1096 path_len = strlen(path);
1097
afe4fd7c
JR
1098 dir_fd = dirfd(dir);
1099 if (dir_fd < 0) {
d7ba1388 1100 PERROR("dirfd");
920a187e
JG
1101 ret = -errno;
1102 goto end;
d7ba1388
MD
1103 }
1104
afe4fd7c 1105 while ((entry = readdir(dir))) {
88ae485a
JR
1106 struct stat st;
1107 size_t name_len;
1108 char filename[PATH_MAX];
1109
d7ba1388 1110 if (!strcmp(entry->d_name, ".")
a424227e 1111 || !strcmp(entry->d_name, "..")) {
d7ba1388 1112 continue;
a424227e 1113 }
88ae485a
JR
1114
1115 name_len = strlen(entry->d_name);
1116 if (path_len + name_len + 2 > sizeof(filename)) {
1117 ERR("Failed to remove file: path name too long (%s/%s)",
1118 path, entry->d_name);
1119 continue;
1120 }
1121
1122 if (snprintf(filename, sizeof(filename), "%s/%s",
1123 path, entry->d_name) < 0) {
1124 ERR("Failed to format path.");
1125 continue;
1126 }
1127
1128 if (stat(filename, &st)) {
1129 PERROR("stat");
1130 continue;
1131 }
1132
1133 if (S_ISDIR(st.st_mode)) {
64803277 1134 char *subpath = calloc<char>(PATH_MAX);
afe4fd7c
JR
1135
1136 if (!subpath) {
1137 PERROR("zmalloc path");
1138 ret = -1;
1139 goto end;
1140 }
1141 strncpy(subpath, path, PATH_MAX);
1142 subpath[PATH_MAX - 1] = '\0';
1143 strncat(subpath, "/",
1144 PATH_MAX - strlen(subpath) - 1);
1145 strncat(subpath, entry->d_name,
1146 PATH_MAX - strlen(subpath) - 1);
1147
1148 ret = delete_dir_recursive(subpath);
1149 free(subpath);
1150 if (ret) {
83f4233d 1151 /* Error occurred, abort traversal. */
afe4fd7c
JR
1152 goto end;
1153 }
88ae485a 1154 } else if (S_ISREG(st.st_mode)) {
afe4fd7c
JR
1155 ret = unlinkat(dir_fd, entry->d_name, 0);
1156 if (ret) {
1157 PERROR("Unlinking '%s'", entry->d_name);
1158 goto end;
1159 }
88ae485a 1160 } else {
d7ba1388
MD
1161 ret = -EINVAL;
1162 goto end;
1163 }
1164 }
1165end:
afe4fd7c
JR
1166 if (!ret) {
1167 ret = rmdir(path);
1168 if (ret) {
1169 PERROR("rmdir '%s'", path);
1170 }
1171 }
1172 closeret = closedir(dir);
d7ba1388
MD
1173 if (closeret) {
1174 PERROR("closedir");
1175 }
ef6fc488 1176end_no_closedir:
d7ba1388
MD
1177 return ret;
1178}
1179
d7ba1388 1180static
53866dcb 1181int view_trace(const char *trace_path, char *viewer_path)
d7ba1388
MD
1182{
1183 pid_t pid;
1184
1185 pid = fork();
1186 if (pid < 0) {
1187 /* Error */
1188 PERROR("fork");
1189 return -1;
1190 } else if (pid > 0) {
1191 /* Parent */
1192 int status;
1193
1194 pid = waitpid(pid, &status, 0);
1195 if (pid < 0 || !WIFEXITED(status)) {
1196 return -1;
1197 }
1198 } else {
1199 /* Child */
1200 int ret;
1201
53866dcb 1202 ret = spawn_viewer(trace_path, viewer_path, false);
d7ba1388 1203 if (ret) {
d7ba1388
MD
1204 exit(EXIT_FAILURE);
1205 }
53866dcb
FD
1206 /* Never reached */
1207 exit(EXIT_SUCCESS);
d7ba1388
MD
1208 }
1209 return 0;
1210}
1211
1212/*
1213 * main
1214 */
1215int main(int argc, char *argv[])
1216{
aa25d686
JG
1217 int ret;
1218 bool has_warning = false;
d7ba1388
MD
1219 const char *output_path = NULL;
1220 char tmppath[] = "/tmp/lttng-crash-XXXXXX";
1221
1222 progname = argv[0] ? argv[0] : "lttng-crash";
1223
1224 ret = parse_args(argc, argv);
1225 if (ret > 0) {
aa25d686 1226 goto end;
d7ba1388 1227 } else if (ret < 0) {
aa25d686
JG
1228 has_warning = true;
1229 goto end;
d7ba1388
MD
1230 }
1231
1232 if (opt_output_path) {
1233 output_path = opt_output_path;
1234 ret = mkdir(output_path, S_IRWXU | S_IRWXG);
1235 if (ret) {
1236 PERROR("mkdir");
aa25d686
JG
1237 has_warning = true;
1238 goto end;
d7ba1388
MD
1239 }
1240 } else {
1241 output_path = mkdtemp(tmppath);
1242 if (!output_path) {
1243 PERROR("mkdtemp");
aa25d686
JG
1244 has_warning = true;
1245 goto end;
d7ba1388
MD
1246 }
1247 }
1248
40b4fee7 1249 ret = extract_trace_recursive(output_path, the_input_path);
d7ba1388 1250 if (ret < 0) {
aa25d686
JG
1251 has_warning = true;
1252 goto end;
d7ba1388 1253 } else if (ret > 0) {
aa25d686
JG
1254 /* extract_trace_recursive reported a warning. */
1255 has_warning = true;
d7ba1388
MD
1256 }
1257 if (!opt_output_path) {
1258 /* View trace */
53866dcb 1259 ret = view_trace(output_path, opt_viewer_path);
aa25d686
JG
1260 if (ret) {
1261 has_warning = true;
1262 }
d7ba1388 1263 /* unlink temporary trace */
afe4fd7c 1264 ret = delete_dir_recursive(output_path);
aa25d686
JG
1265 if (ret) {
1266 has_warning = true;
1267 }
d7ba1388 1268 }
aa25d686
JG
1269end:
1270 exit(has_warning ? EXIT_FAILURE : EXIT_SUCCESS);
d7ba1388 1271}
This page took 0.163537 seconds and 4 git commands to generate.