diff options
author | Lennart Poettering <lennart@poettering.net> | 2012-04-17 18:15:11 +0200 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2012-04-17 18:15:11 +0200 |
commit | 96546bc06372cecae9b809625710ff0d201f6063 (patch) | |
tree | d82ed34b29494672dd5d395c9aebaa4ca03e7584 | |
parent | 1fbf33ca0fa6c27a4ee1e00aa85b4fd4c8984867 (diff) |
properly implement mkminidump tool
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | Makefile | 6 | ||||
-rw-r--r-- | generate.c | 68 | ||||
-rw-r--r-- | minidump.c | 3 | ||||
-rw-r--r-- | mkminidump.c | 268 |
5 files changed, 275 insertions, 72 deletions
@@ -2,4 +2,4 @@ core core.* *.o segfault -generate +mkminidump @@ -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; -} @@ -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; +} |