summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2012-04-17 18:15:11 +0200
committerLennart Poettering <lennart@poettering.net>2012-04-17 18:15:11 +0200
commit96546bc06372cecae9b809625710ff0d201f6063 (patch)
treed82ed34b29494672dd5d395c9aebaa4ca03e7584
parent1fbf33ca0fa6c27a4ee1e00aa85b4fd4c8984867 (diff)
properly implement mkminidump tool
-rw-r--r--.gitignore2
-rw-r--r--Makefile6
-rw-r--r--generate.c68
-rw-r--r--minidump.c3
-rw-r--r--mkminidump.c268
5 files changed, 275 insertions, 72 deletions
diff --git a/.gitignore b/.gitignore
index 6bd832d..0d7abb8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,4 +2,4 @@ core
core.*
*.o
segfault
-generate
+mkminidump
diff --git a/Makefile b/Makefile
index 4e6c852..d11153e 100644
--- a/Makefile
+++ b/Makefile
@@ -1,8 +1,8 @@
CFLAGS=-Wextra -Wall -O0 -g -D_GNU_SOURCE -pthread
-all: segfault generate core
+all: segfault mkminidump core
-generate: generate.o coredump.h coredump.o minidump.o minidump.h format.h
+mkminidump: mkminidump.o coredump.h coredump.o minidump.o minidump.h format.h
$(CC) $(CFLAGS) $(LIBS) $^ -o $@
segfault: segfault.c
@@ -12,4 +12,4 @@ core: segfault
( ./segfault ||: ) > /dev/null 2>&1
clean:
- rm -f core.* core segfault generate
+ rm -f core.* core segfault mkminidump
diff --git a/generate.c b/generate.c
deleted file mode 100644
index a1ef9eb..0000000
--- a/generate.c
+++ /dev/null
@@ -1,68 +0,0 @@
-
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#include <stdio.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <string.h>
-
-#include "minidump.h"
-
-int main(int argc, char *argv[]) {
- int r;
- int fd = -1;
- unsigned long l;
- char *p = NULL;
- void *minidump = NULL;
- size_t minidump_size = 0;
-
- if (argc != 2) {
- fprintf(stderr, "Expecting file name as sole argument.\n");
- r = -EINVAL;
- goto fail;
- }
-
- errno = 0;
- l = strtoul(argv[1], &p, 10);
- if (errno == 0 && p && *p == 0 && l > 0) {
- coredump_show(stderr, (pid_t) l, -1);
- /* r = minidump_make((pid_t) l, -1, &minidump, &minidump_size); */
- } else {
- fd = open(argc >= 2 ? argv[1] : "core", O_RDONLY|O_CLOEXEC);
- if (fd < 0) {
- fprintf(stderr, "Failed to open core dump: %m\n");
- r = -errno;
- goto fail;
- }
-
- coredump_show(stderr, 0, fd);
- /* r = minidump_make(0, fd, &minidump, &minidump_size); */
- }
- r = 0;
-
- if (r < 0) {
- fprintf(stderr, "Failed to generate minidump: %s\n", strerror(-r));
- goto fail;
- }
-
- fwrite(minidump, 1, minidump_size, stdout);
- fflush(stdout);
-
- if (ferror(stdout)) {
- fprintf(stderr, "Failed to write minidump: %m\n");
- r = -errno;
- goto fail;
- }
-
- r = 0;
-
-fail:
- if (fd >= 0)
- close(fd);
-
- free(minidump);
-
- return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
-}
diff --git a/minidump.c b/minidump.c
index 0d0b8d6..9395f74 100644
--- a/minidump.c
+++ b/minidump.c
@@ -794,6 +794,7 @@ static int add_mapping(struct context *c, unsigned long start, unsigned long end
c->maps[j].extent.address = start;
c->maps[j].extent.size = (size_t) (end - start);
c->maps[j].name = name ? strdup(name) : NULL;
+ c->maps[j].build_id = NULL;
if (name)
fprintf(stderr, "Added mapping %u address=0x%lx size=0x%lx name=%s\n", j, c->maps[j].extent.address, c->maps[j].extent.size, name);
@@ -1603,6 +1604,8 @@ static int write_minidump(struct context *c) {
static int write_minicore(struct context *c) {
assert(c);
+ /* FIXME */
+
return 0;
}
diff --git a/mkminidump.c b/mkminidump.c
new file mode 100644
index 0000000..4a88870
--- /dev/null
+++ b/mkminidump.c
@@ -0,0 +1,268 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <getopt.h>
+#include <assert.h>
+
+#include "minidump.h"
+
+static char *arg_source = NULL;
+static pid_t arg_pid = 0;
+static char *arg_minidump = NULL;
+static char *arg_minicore = NULL;
+
+static int help(void) {
+
+ printf("%s [OPTIONS...] [FILE]\n\n"
+ "Generate, decode or convert a mindump or minicore.\n\n"
+ " -h --help Show this help\n"
+ " -p --pid=PID Generate from PID\n"
+ " -d --minidump[=FILE] Generate a minidump\n"
+ " -c --minicore[=FILE] Generate a minicore\n",
+ program_invocation_short_name);
+
+ return 0;
+}
+
+static int parse_argv(int argc, char *argv[]) {
+
+ enum {
+ ARG_VERSION = 0x100
+ };
+
+ static const struct option options[] = {
+ { "help", no_argument, NULL, 'h' },
+ { "pid", required_argument, NULL, 'p' },
+ { "minidump", optional_argument, NULL, 'd' },
+ { "minicore", optional_argument, NULL, 'c' },
+ { NULL, 0, NULL, 0 }
+ };
+
+ int c;
+
+ assert(argc >= 0);
+ assert(argv);
+
+ while ((c = getopt_long(argc, argv, "hp:d::c::", options, NULL)) >= 0) {
+
+ switch (c) {
+
+ case 'h':
+ help();
+ return 0;
+
+ case 'p': {
+ unsigned long ul;
+ char *e;
+
+ errno = 0;
+ ul = strtoul(optarg, &e, 10);
+ if (errno != 0 || !e || *e || ul <= 0) {
+ fprintf(stderr, "Failed to parse PID argument.\n");
+ return -EINVAL;
+ }
+
+ arg_pid = (pid_t) ul;
+ break;
+ }
+
+ case 'd':
+ arg_minidump = optarg ? optarg : "-";
+ break;
+
+ case 'c':
+ arg_minicore = optarg ? optarg : "-";
+ break;
+
+ case '?':
+ return -EINVAL;
+
+ default:
+ fprintf(stderr, "Unknown option code %c\n", c);
+ return -EINVAL;
+ }
+ }
+
+ if (optind >= argc && !arg_pid) {
+ /* No source arguments specified at all */
+ help();
+ return 0;
+ }
+
+ if (argc > optind+1) {
+ /* More than one source argument specified */
+ help();
+ return -EINVAL;
+ }
+
+ if (optind < argc)
+ arg_source = argv[optind];
+
+ return 1;
+}
+
+static int output_and_free(const char *path, void **buffer, size_t *buffer_size) {
+ FILE *f, *toclose;
+ int r = 0;
+
+ assert(buffer);
+ assert(*buffer);
+ assert(buffer_size);
+ assert(*buffer_size > 0);
+
+ if (!path || strcmp(path, "-")) {
+ f = stdout;
+ toclose = NULL;
+ } else {
+ f = fopen(path, "we");
+ if (!f) {
+ r = -errno;
+ fprintf(stderr, "Failed to write output: %m\n");
+ goto finish;
+ }
+ toclose = f;
+ }
+
+ fwrite(*buffer, 1, *buffer_size, f);
+ fflush(f);
+
+ if (ferror(f)) {
+ r = -errno;
+ fprintf(stderr, "Failed to write output: %m\n");
+ goto finish;
+ }
+
+ free(*buffer);
+ *buffer = NULL;
+ *buffer_size = 0;
+
+finish:
+ if (toclose)
+ fclose(toclose);
+
+ return r;
+}
+
+int main(int argc, char *argv[]) {
+ int r;
+ int fd = -1;
+ void *buffer = NULL;
+ size_t buffer_size = 0;
+
+ r = parse_argv(argc, argv);
+ if (r <= 0)
+ return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+
+ if (arg_source) {
+ if (strcmp(arg_source, "-") == 0)
+ fd = STDIN_FILENO;
+ else {
+ fd = open(arg_source, O_RDONLY|O_CLOEXEC);
+
+ if (fd < 0) {
+ r = -errno;
+ fprintf(stderr, "Failed to open source file: %m\n");
+ goto finish;
+ }
+ }
+ }
+
+ if (arg_pid > 0) {
+ /* If a PID specified, the fd definitely refers to a
+ * process or a coredump of some kind */
+
+ if (arg_minidump) {
+ r = minidump_make(arg_pid, fd, &buffer, &buffer_size);
+ if (r < 0) {
+ fprintf(stderr, "Failed to generate minidump: %s\n", strerror(-r));
+ goto finish;
+ }
+
+ r = output_and_free(arg_minidump, &buffer, &buffer_size);
+ if (r < 0)
+ goto finish;
+ }
+
+ if (arg_minicore) {
+ r = minicore_make(arg_pid, fd, &buffer, &buffer_size);
+ if (r < 0) {
+ fprintf(stderr, "Failed to generate minicore: %s\n", strerror(-r));
+ goto finish;
+ }
+
+ r = output_and_free(arg_minidump, &buffer, &buffer_size);
+ if (r < 0)
+ goto finish;
+ }
+
+ if (!arg_minidump && !arg_minicore) {
+ r = coredump_show(stdout, arg_pid, fd);
+ if (r < 0) {
+ fprintf(stderr, "Failed to decode coredump: %s\n", strerror(-r));
+ goto finish;
+ }
+ }
+ } else {
+ assert(fd >= 0);
+
+ /* No PID specified, so let's guess by the output
+ * parameters */
+
+ if (arg_minicore && arg_minidump) {
+ fprintf(stderr, "Can't convert file into its own type.\n");
+ r = -EINVAL;
+ goto finish;
+ }
+
+ if (arg_minicore) {
+ r = minidump_to_minicore(fd, &buffer, &buffer_size);
+ if (r < 0) {
+ fprintf(stderr, "Failed to convert minidump: %s\n", strerror(-r));
+ goto finish;
+ }
+
+ r = output_and_free(arg_minidump, &buffer, &buffer_size);
+ if (r < 0)
+ goto finish;
+ }
+
+ if (arg_minidump) {
+ r = minicore_make(0, fd, &buffer, &buffer_size);
+ if (r < 0) {
+ fprintf(stderr, "Failed to convert coredump: %s\n", strerror(-r));
+ goto finish;
+ }
+
+ r = output_and_free(arg_minidump, &buffer, &buffer_size);
+ if (r < 0)
+ goto finish;
+ }
+
+ if (!arg_minidump && !arg_minicore) {
+
+ r = minidump_show(stdout, fd);
+ if (r == -EINVAL)
+ r = coredump_show(stdout, 0, fd);
+
+ if (r < 0) {
+ fprintf(stderr, "Failed to decode coredump or minidump: %s\n", strerror(-r));
+ goto finish;
+ }
+ }
+ }
+
+ r = 0;
+
+finish:
+ if (fd > 2)
+ close(fd);
+
+ free(buffer);
+
+ return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+}