From m.moscicki2 at partner.samsung.com Tue May 21 14:52:36 2019 From: m.moscicki2 at partner.samsung.com (Mateusz Moscicki) Date: Tue, 21 May 2019 14:52:36 +0200 Subject: [minicoredumper] [PATCH 00/14] Set of different changes References: Message-ID: <1558443170-15123-1-git-send-email-m.moscicki2@partner.samsung.com> I realize that these changes don't have to be consistent with the author's vision, but we just wanted to share our work, because some of them may be useful. Mateusz Moscicki (13): minicoredumper: Save command line arguments in cmd_parameters structure minicoredumper: Add command line options to specify the dst_dir and coredump file name minicoredumper: dump NT_GNU_BUILD_ID notes minicoredumper: Don't use compression if the compressor is an empty string minicoredumper: Add checking if the mapped memory regions are in the coredump minicoredumper: Fix Coverity and SVACE warnings minicoredumper: Log errors for copy_link() and copy_file() minicoredumper: Write an uncompressed core and a fatcore as a sparse file minicoredumper: Ignore errors during data copy minicoredumper: Fix checking if memory regions can be merged minicoredumper: Fix writing/reading from file descriptor minicoredumper: Add an option to dump memory pages pointed by registers minicoredumper: Add option to exclude specified files from copying from proc ?ukasz Stelmach (1): minicoredumper: read stack pointer from registers etc/minicoredumper/generic.recept.json | 9 +- src/common/elf_dumplist.c | 16 +- src/minicoredumper/corestripper.c | 997 ++++++++++++++++-------- src/minicoredumper/corestripper.h | 25 +- src/minicoredumper/minicoredumper.1 | 12 + src/minicoredumper/minicoredumper.recept.json.5 | 19 + src/minicoredumper/prog_config.c | 81 +- src/minicoredumper/prog_config.h | 8 + 8 files changed, 796 insertions(+), 371 deletions(-) -- 2.7.4 From m.moscicki2 at partner.samsung.com Tue May 21 14:52:38 2019 From: m.moscicki2 at partner.samsung.com (Mateusz Moscicki) Date: Tue, 21 May 2019 14:52:38 +0200 Subject: [minicoredumper] [PATCH 02/14] minicoredumper: Add command line options to specify the dst_dir and coredump file name In-Reply-To: <1558443170-15123-1-git-send-email-m.moscicki2@partner.samsung.com> References: <1558443170-15123-1-git-send-email-m.moscicki2@partner.samsung.com> Message-ID: <1558443170-15123-3-git-send-email-m.moscicki2@partner.samsung.com> Specyfying these values may be needed when the minicoredumper is run by another script or program. This change doesn't break compatibility. Change-Id: If4922bf6ca620607c4f5b8a1f79b7e7022d487eb --- src/minicoredumper/corestripper.c | 69 +++++++++++++++++++++++++++---------- src/minicoredumper/corestripper.h | 2 ++ src/minicoredumper/minicoredumper.1 | 12 +++++++ 3 files changed, 65 insertions(+), 18 deletions(-) diff --git a/src/minicoredumper/corestripper.c b/src/minicoredumper/corestripper.c index 48fa4e5..350927f 100644 --- a/src/minicoredumper/corestripper.c +++ b/src/minicoredumper/corestripper.c @@ -52,6 +52,10 @@ #define PTRACE_INTERRUPT 0x4207 #endif +#define DEFAULT_BASE_NAME "core" + +char cmd_options[] = "o:d:"; + static struct dump_info *global_di; static long PAGESZ; @@ -632,7 +636,7 @@ static int init_di(struct dump_info *di) return 1; if (di->cmd_params->signum != 0) { - if (asprintf(&tmp_path, "/core-%s-%d", comm_base, + if (asprintf(&tmp_path, "/%s-%s-%d", di->cmd_params->base_name, comm_base, di->cmd_params->pid) == -1) { return 1; } @@ -648,7 +652,7 @@ static int init_di(struct dump_info *di) shm_unlink(tmp_path); free(tmp_path); - if (asprintf(&tmp_path, "%s/core", di->dst_dir) == -1) + if (asprintf(&tmp_path, "%s/%s", di->dst_dir, di->cmd_params->base_name) == -1) return 1; di->core_path = tmp_path; @@ -1111,7 +1115,7 @@ static int open_compressor(struct dump_info *di, const char *core_suffix, *path = NULL; - if (asprintf(&tmp_path, "%s/core%s.%s", di->dst_dir, core_suffix, + if (asprintf(&tmp_path, "%s/%s%s.%s", di->dst_dir, di->cmd_params->base_name, core_suffix, ext ? ext : "compressed") == -1) { return -1; } @@ -3629,8 +3633,13 @@ static int do_all_dumps(struct dump_info *di) comm_base = p + 1; } - di->dst_dir = alloc_dst_dir(di->cmd_params->timestamp, cfg->base_dir, - comm_base, di->cmd_params->pid); + if (!di->cmd_params->dst_dir) { + di->dst_dir = alloc_dst_dir(di->cmd_params->timestamp, cfg->base_dir, + comm_base, di->cmd_params->pid); + } else { + di->dst_dir = strdup(di->cmd_params->dst_dir); + } + if (!di->dst_dir) return 1; @@ -3724,36 +3733,60 @@ typedef enum { struct cmd_parameters* parse_args(char *argv[], int argc) { - if (argc < (ARG_EXE_NAME + 1) || argc > (ARG_CONF_PATH + 1)) - fatal("wrong amount of command line parameters"); - struct cmd_parameters *cmd_params = (struct cmd_parameters*)malloc(sizeof(struct cmd_parameters)); if (cmd_params == NULL) fatal("malloc for cmd_parameters error: %m"); char *p; + int opt; + + cmd_params->base_name = NULL; + cmd_params->dst_dir = NULL; - cmd_params->pid = strtol(argv[ARG_PID], &p, 10); + while ((opt = getopt(argc, argv, cmd_options)) != -1) { + switch (opt) { + case 'o': + cmd_params->base_name = optarg; + break; + case 'd': + cmd_params->dst_dir = optarg; + break; + } + } + + int opts_count = optind - 1; + + if (argc < (ARG_EXE_NAME + opts_count + 1) || argc > (ARG_CONF_PATH + opts_count + 1)) { + fatal("wrong amount of command line parameters: %d", opts_count); + } + + if (cmd_params->base_name == NULL) + cmd_params->base_name = DEFAULT_BASE_NAME; + + cmd_params->pid = strtol(argv[ARG_PID + opts_count], &p, 10); if (*p != 0) fatal("invalid pid"); - cmd_params->uid = strtol(argv[ARG_UID], &p, 10); + info("pid: %d", cmd_params->pid); + cmd_params->uid = strtol(argv[ARG_UID + opts_count], &p, 10); if (*p != 0) fatal("invalid uid"); - cmd_params->gid = strtol(argv[ARG_GID], &p, 10); + cmd_params->gid = strtol(argv[ARG_GID + opts_count], &p, 10); + if (*p != 0) fatal("invalid gid"); + info("gid: %d", cmd_params->gid); - cmd_params->signum = strtol(argv[ARG_SIGNUM], &p, 10); + cmd_params->signum = strtol(argv[ARG_SIGNUM + opts_count], &p, 10); if (*p != 0) fatal("invalid signum"); - cmd_params->timestamp = strtol(argv[ARG_TIMESTAMP], &p, 10); + cmd_params->timestamp = strtol(argv[ARG_TIMESTAMP + opts_count], &p, 10); if (*p != 0) fatal("invalid timestamp"); - cmd_params->hostname = argv[ARG_HOSTNAME]; + cmd_params->hostname = argv[ARG_HOSTNAME + opts_count]; if (!cmd_params->hostname) fatal("invalid hostname"); @@ -3761,11 +3794,11 @@ struct cmd_parameters* parse_args(char *argv[], int argc) if (!cmd_params->exe_name) fatal("invalid exe filename"); - if (argc == ARG_CONF_PATH) { + if (argc == ARG_CONF_PATH + opts_count) { cmd_params->cfg_path = MCD_CONF_PATH "/minicoredumper.cfg.json"; - } else if (argc == ARG_CONF_PATH + 1) { - info("using custom minicoredumper cfg: %s", argv[ARG_CONF_PATH]); - cmd_params->cfg_path = argv[ARG_CONF_PATH]; + } else if (argc == ARG_CONF_PATH + opts_count + 1) { + info("using custom minicoredumper cfg: %s", argv[ARG_CONF_PATH + opts_count]); + cmd_params->cfg_path = argv[ARG_CONF_PATH + opts_count]; } else { fatal("wrong arg count, check /proc/sys/kernel/core_pattern"); } diff --git a/src/minicoredumper/corestripper.h b/src/minicoredumper/corestripper.h index e1511f8..22da645 100644 --- a/src/minicoredumper/corestripper.h +++ b/src/minicoredumper/corestripper.h @@ -51,6 +51,8 @@ struct cmd_parameters { char *hostname; char *cfg_path; char *exe_name; + char *dst_dir; + char *base_name; }; struct dump_info { diff --git a/src/minicoredumper/minicoredumper.1 b/src/minicoredumper/minicoredumper.1 index e2212dd..91c94e2 100644 --- a/src/minicoredumper/minicoredumper.1 +++ b/src/minicoredumper/minicoredumper.1 @@ -35,6 +35,18 @@ dump facility. By default the main configuration file is: .PP but can be overridden if the optional 8th argument is specified. .PP +Additionally these options can be specified: +.PP +.TP +.BI \-o \ core_filename +Specify coredump base file name. \fBtar\fR +or +.BR gz +extension will be added if needed. +.TP +.BI \-d \ dest_dir +Specify the output directory. +.PP .BR minicoredumper uses .BR syslog (3) -- 2.7.4 From m.moscicki2 at partner.samsung.com Tue May 21 14:52:37 2019 From: m.moscicki2 at partner.samsung.com (Mateusz Moscicki) Date: Tue, 21 May 2019 14:52:37 +0200 Subject: [minicoredumper] [PATCH 01/14] minicoredumper: Save command line arguments in cmd_parameters structure In-Reply-To: <1558443170-15123-1-git-send-email-m.moscicki2@partner.samsung.com> References: <1558443170-15123-1-git-send-email-m.moscicki2@partner.samsung.com> Message-ID: <1558443170-15123-2-git-send-email-m.moscicki2@partner.samsung.com> Change-Id: I01baf48d743d76599a68c5a6a358092d0c24ef27 --- src/minicoredumper/corestripper.c | 276 +++++++++++++++++++++++--------------- src/minicoredumper/corestripper.h | 20 ++- 2 files changed, 178 insertions(+), 118 deletions(-) diff --git a/src/minicoredumper/corestripper.c b/src/minicoredumper/corestripper.c index d96d1df..48fa4e5 100644 --- a/src/minicoredumper/corestripper.c +++ b/src/minicoredumper/corestripper.c @@ -379,7 +379,7 @@ static int get_task_list(struct dump_info *di) di->tsks = NULL; di->ntsks = 0; - snprintf(buf, sizeof(buf), "/proc/%d/task", di->pid); + snprintf(buf, sizeof(buf), "/proc/%d/task", di->cmd_params->pid); d = opendir(buf); if (!d) @@ -573,7 +573,7 @@ static char *alloc_dst_dir(time_t timestamp, const char *base_dir, return tmp_path; } -static int init_di(struct dump_info *di, int argc, char *argv[]) +static int init_di(struct dump_info *di) { const char *recept; char *comm_base; @@ -590,52 +590,22 @@ static int init_di(struct dump_info *di, int argc, char *argv[]) di->core_fd = -1; di->fatcore_fd = -1; - di->pid = strtol(argv[1], &p, 10); - if (*p != 0) - return 1; - - di->uid = strtol(argv[2], &p, 10); - if (*p != 0) - return 1; + di->cfg = init_config(di->cmd_params->cfg_path); - di->gid = strtol(argv[3], &p, 10); - if (*p != 0) - return 1; - - di->signum = strtol(argv[4], &p, 10); - if (*p != 0) - return 1; + if (!di->cfg) + fatal("unable to init config"); - di->timestamp = strtol(argv[5], &p, 10); - if (*p != 0) - return 1; + check_config(di->cfg); - di->hostname = argv[6]; - if (!di->hostname) - return 1; - di->comm = alloc_comm(argv[7], di->pid); + di->comm = alloc_comm(di->cmd_params->exe_name, di->cmd_params->pid); if (!di->comm) - return 1; + fatal("error while reading the comm file"); - di->exe = alloc_exe(di->pid); + di->exe = alloc_exe(di->cmd_params->pid); if (!di->exe) - return 1; + fatal("error while reading the exe file"); - if (argc == 8) { - di->cfg = init_config(MCD_CONF_PATH - "/minicoredumper.cfg.json"); - } else if (argc == 9) { - info("using custom minicoredumper cfg: %s", argv[8]); - di->cfg = init_config(argv[8]); - } else { - fatal("wrong arg count, check /proc/sys/kernel/core_pattern"); - } - - if (!di->cfg) - fatal("unable to init config"); - - check_config(di->cfg); info("comm: %s", di->comm); info("exe: %s", di->exe); @@ -661,9 +631,9 @@ static int init_di(struct dump_info *di, int argc, char *argv[]) if (get_task_list(di) != 0) return 1; - if (di->signum != 0) { + if (di->cmd_params->signum != 0) { if (asprintf(&tmp_path, "/core-%s-%d", comm_base, - di->pid) == -1) { + di->cmd_params->pid) == -1) { return 1; } @@ -714,7 +684,7 @@ static int init_di(struct dump_info *di, int argc, char *argv[]) free(tmp_path); } - if (asprintf(&tmp_path, "/proc/%i/mem", di->pid) == -1) + if (asprintf(&tmp_path, "/proc/%i/mem", di->cmd_params->pid) == -1) return 1; di->mem_fd = open(tmp_path, O_RDONLY); @@ -752,8 +722,8 @@ static int init_log(struct dump_info *di) fprintf(di->info_file, "Core Dump Log\n"); fprintf(di->info_file, "-------------\n"); fprintf(di->info_file, "Program: %s\n", di->exe); - fprintf(di->info_file, "PID: %i UID: %i GID: %i\n", di->pid, - di->uid, di->gid); + fprintf(di->info_file, "PID: %i UID: %i GID: %i\n", di->cmd_params->pid, + di->cmd_params->uid, di->cmd_params->gid); return 0; } @@ -2203,7 +2173,7 @@ static int dump_maps(struct dump_info *di, int get_only) goto out_err; /* open maps file */ - snprintf(buf, MAPS_LINE_MAXSIZE, "/proc/%d/maps", di->pid); + snprintf(buf, MAPS_LINE_MAXSIZE, "/proc/%d/maps", di->cmd_params->pid); f = fopen(buf, "r"); if (!f) goto out_err; @@ -2629,11 +2599,11 @@ static int dump_data_content_file(struct dump_info *di, mkdir(tmp_path, 0700); /* create dumps pid sub-directory */ - snprintf(tmp_path, len, "%s/dumps/%i", di->dst_dir, di->pid); + snprintf(tmp_path, len, "%s/dumps/%i", di->dst_dir, di->cmd_params->pid); mkdir(tmp_path, 0700); /* open text file for output */ - snprintf(tmp_path, len, "%s/dumps/%i/%s", di->dst_dir, di->pid, + snprintf(tmp_path, len, "%s/dumps/%i/%s", di->dst_dir, di->cmd_params->pid, dd->ident); if (dd->type == MCD_BIN) file = fopen(tmp_path, "wx"); @@ -2850,12 +2820,12 @@ static void copy_proc_files(struct dump_info *di, int tasks, const char *name, snprintf(path, size, "%s/proc", di->dst_dir); mkdir(path, 0700); - snprintf(path, size, "%s/proc/%d", di->dst_dir, di->pid); + snprintf(path, size, "%s/proc/%d", di->dst_dir, di->cmd_params->pid); mkdir(path, 0700); /* handle non-task file */ if (!tasks) { - snprintf(path, size, "%s/proc/%d/%s", di->dst_dir, di->pid, + snprintf(path, size, "%s/proc/%d/%s", di->dst_dir, di->cmd_params->pid, name); if (link) copy_link(path, path + base_len); @@ -2865,18 +2835,18 @@ static void copy_proc_files(struct dump_info *di, int tasks, const char *name, return; } - snprintf(path, size, "%s/proc/%d/task", di->dst_dir, di->pid); + snprintf(path, size, "%s/proc/%d/task", di->dst_dir, di->cmd_params->pid); mkdir(path, 0700); for (i = 0 ; i < di->ntsks; i++) { snprintf(path, size, "%s/proc/%d/task/%d", di->dst_dir, - di->pid, di->tsks[i]); + di->cmd_params->pid, di->tsks[i]); mkdir(path, 0700); /* handle the normal task case */ if (!do_fds) { snprintf(path, size, "%s/proc/%d/task/%d/%s", - di->dst_dir, di->pid, di->tsks[i], name); + di->dst_dir, di->cmd_params->pid, di->tsks[i], name); if (link) copy_link(path, path + base_len); @@ -2887,7 +2857,7 @@ static void copy_proc_files(struct dump_info *di, int tasks, const char *name, /* special case: copy the symlinks in the fd directory */ snprintf(path, size, "%s/proc/%d/task/%d/fd", di->dst_dir, - di->pid, di->tsks[i]); + di->cmd_params->pid, di->tsks[i]); mkdir(path, 0700); d = opendir(path + base_len); @@ -2904,7 +2874,7 @@ static void copy_proc_files(struct dump_info *di, int tasks, const char *name, continue; snprintf(path, size, "%s/proc/%d/task/%d/fd/%s", - di->dst_dir, di->pid, di->tsks[i], + di->dst_dir, di->cmd_params->pid, di->tsks[i], de->d_name); copy_link(path, path + base_len); @@ -2933,7 +2903,7 @@ static int get_robust_mutex_list(struct dump_info *di) size_t len; long ret; - ret = __sys_get_robust_list(di->pid, + ret = __sys_get_robust_list(di->cmd_params->pid, (struct robust_list_head **)&l_head, &len); if (ret != 0 || len != sizeof(struct robust_list_head)) return -1; @@ -3081,7 +3051,7 @@ ps_err_e ps_lsetfpregs(struct ps_prochandle *ph, lwpid_t lwpid, pid_t ps_getpid(struct ps_prochandle *ph) { - return ph->di->pid; + return ph->di->cmd_params->pid; } ps_err_e ps_pglobal_lookup(struct ps_prochandle *ph, const char *object_name, @@ -3247,7 +3217,7 @@ static int get_so_list(struct dump_info *di) int ret; int fd; - if (asprintf(&filename, "/proc/%d/auxv", di->pid) == -1) + if (asprintf(&filename, "/proc/%d/auxv", di->cmd_params->pid) == -1) return -1; fd = open(filename, O_RDONLY); @@ -3409,11 +3379,12 @@ static int add_dumplist_section(struct dump_info *di) } #endif -static void do_dump(struct dump_info *di, int argc, char *argv[]) +static void do_dump(struct dump_info *di) { int ret; - ret = init_di(di, argc, argv); + ret = init_di(di); + if (ret == 1) { info("unable to create new dump info instance"); goto out; @@ -3594,60 +3565,59 @@ out: munmap(sh, map_size); } -static int do_all_dumps(struct dump_info *di, int argc, char *argv[]) +static struct cmd_parameters* copy_cmd_params(struct cmd_parameters* cmd_params) +{ + struct cmd_parameters *new_params = (struct cmd_parameters*)malloc(sizeof(struct cmd_parameters)); + if (new_params == NULL) + return NULL; + + new_params->pid = cmd_params->pid; + new_params->uid = cmd_params->uid; + new_params->gid = cmd_params->gid; + new_params->signum = cmd_params->signum; + new_params->timestamp = cmd_params->timestamp; + new_params->hostname = cmd_params->hostname; + new_params->cfg_path = cmd_params->cfg_path; + new_params->exe_name = cmd_params->exe_name; + + return new_params; +} + +static int do_all_dumps(struct dump_info *di) { struct config *cfg = NULL; const char *recept; bool live_dumper; char *comm_base; - pid_t core_pid; - long timestamp; char *comm; char *exe; char *p; - char *ext_argv[10] = { - argv[0], - argv[1], - argv[2], - argv[3], - "0", - argv[5], - argv[6], - "", - argv[8], - NULL - }; - - if (argc == 8) { - cfg = init_config(MCD_CONF_PATH "/minicoredumper.cfg.json"); - } else if (argc == 9) { - info("using custom minicoredumper cfg: %s", argv[8]); - cfg = init_config(argv[8]); - } else { - fatal("wrong arg count, check /proc/sys/kernel/core_pattern"); - } + + struct cmd_parameters *orig_params, *ext_params; + + ext_params = copy_cmd_params(di->cmd_params); + if (ext_params == NULL) + fatal("malloc for ext_params error: %m"); + + cfg = init_config(di->cmd_params->cfg_path); if (!cfg) fatal("unable to init config"); check_config(cfg); - core_pid = strtol(argv[1], &p, 10); - if (*p != 0) - return 1; - - timestamp = strtol(argv[5], &p, 10); - if (*p != 0) - return 1; + ext_params->signum = 0; + ext_params->exe_name = ""; - comm = alloc_comm(argv[7], core_pid); + comm = alloc_comm(di->cmd_params->exe_name, di->cmd_params->pid); if (!comm) return 1; - if (core_pid == 0) + if (di->cmd_params->pid == 0) exe = strdup(""); else - exe = alloc_exe(core_pid); + exe = alloc_exe(di->cmd_params->pid); + if (!exe) return 1; @@ -3659,8 +3629,8 @@ static int do_all_dumps(struct dump_info *di, int argc, char *argv[]) comm_base = p + 1; } - di->dst_dir = alloc_dst_dir(timestamp, cfg->base_dir, - comm_base, core_pid); + di->dst_dir = alloc_dst_dir(di->cmd_params->timestamp, cfg->base_dir, + comm_base, di->cmd_params->pid); if (!di->dst_dir) return 1; @@ -3683,13 +3653,13 @@ static int do_all_dumps(struct dump_info *di, int argc, char *argv[]) int n; int i; - alloc_registered_pids(core_pid, &pids, &n); + alloc_registered_pids(di->cmd_params->pid, &pids, &n); /* pause all registered tasks */ for (i = 0; i < n; i++) { if (pids[i] == 0) continue; - if (pids[i] == core_pid) + if (pids[i] == di->cmd_params->pid) continue; if (ptrace_tree(PTRACE_SEIZE, pids[i]) != 0) pids[i] = 0; @@ -3697,22 +3667,30 @@ static int do_all_dumps(struct dump_info *di, int argc, char *argv[]) ptrace_tree(PTRACE_INTERRUPT, pids[i]); } + orig_params = di->cmd_params; + di->cmd_params = ext_params; /* dump all registered tasks */ for (i = 0; i < n; i++) { + char *p; if (pids[i] == 0) continue; - if (pids[i] == core_pid) + if (pids[i] == di->cmd_params->pid) continue; snprintf(pidstr, sizeof(pidstr), "%d", pids[i]); - ext_argv[1] = &pidstr[0]; - do_dump(di, argc, ext_argv); + + ext_params->pid = strtol(pidstr, &p, 10); + if (*p != 0) + fatal("invalid pid"); + + do_dump(di); } + di->cmd_params = orig_params; /* resume all registered tasks */ for (i = 0; i < n; i++) { if (pids[i] == 0) continue; - if (pids[i] == core_pid) + if (pids[i] == di->cmd_params->pid) continue; ptrace_tree(PTRACE_DETACH, pids[i]); } @@ -3721,9 +3699,11 @@ static int do_all_dumps(struct dump_info *di, int argc, char *argv[]) free(pids); } - if (core_pid != 0) { + free(ext_params); + + if (di->cmd_params->pid != 0) { /* dump crashed task */ - do_dump(di, argc, argv); + do_dump(di); } free(di->dst_dir); @@ -3731,6 +3711,80 @@ static int do_all_dumps(struct dump_info *di, int argc, char *argv[]) return 0; } +typedef enum { + ARG_PID = 1, + ARG_UID, + ARG_GID, + ARG_SIGNUM, + ARG_TIMESTAMP, + ARG_HOSTNAME, + ARG_EXE_NAME, + ARG_CONF_PATH, +} cmd_prms; + +struct cmd_parameters* parse_args(char *argv[], int argc) +{ + if (argc < (ARG_EXE_NAME + 1) || argc > (ARG_CONF_PATH + 1)) + fatal("wrong amount of command line parameters"); + + struct cmd_parameters *cmd_params = (struct cmd_parameters*)malloc(sizeof(struct cmd_parameters)); + if (cmd_params == NULL) + fatal("malloc for cmd_parameters error: %m"); + + char *p; + + cmd_params->pid = strtol(argv[ARG_PID], &p, 10); + if (*p != 0) + fatal("invalid pid"); + + cmd_params->uid = strtol(argv[ARG_UID], &p, 10); + if (*p != 0) + fatal("invalid uid"); + + cmd_params->gid = strtol(argv[ARG_GID], &p, 10); + if (*p != 0) + fatal("invalid gid"); + + cmd_params->signum = strtol(argv[ARG_SIGNUM], &p, 10); + if (*p != 0) + fatal("invalid signum"); + + cmd_params->timestamp = strtol(argv[ARG_TIMESTAMP], &p, 10); + if (*p != 0) + fatal("invalid timestamp"); + + cmd_params->hostname = argv[ARG_HOSTNAME]; + if (!cmd_params->hostname) + fatal("invalid hostname"); + + cmd_params->exe_name = argv[ARG_EXE_NAME]; + if (!cmd_params->exe_name) + fatal("invalid exe filename"); + + if (argc == ARG_CONF_PATH) { + cmd_params->cfg_path = MCD_CONF_PATH "/minicoredumper.cfg.json"; + } else if (argc == ARG_CONF_PATH + 1) { + info("using custom minicoredumper cfg: %s", argv[ARG_CONF_PATH]); + cmd_params->cfg_path = argv[ARG_CONF_PATH]; + } else { + fatal("wrong arg count, check /proc/sys/kernel/core_pattern"); + } + return cmd_params; +} + +void print_argv(int argc, char *argv[]) +{ + char buff[1024]; + int offset = 0; + for (int i = 0; i < argc; i++) { + int ret = snprintf(&buff[offset], 1024-offset, " %s", argv[i]); + if (ret < 0) + fatal("print command line arguments error"); + offset += ret; + } + info("argv:%s", buff); +} + int main(int argc, char *argv[]) { struct dump_info di; @@ -3752,14 +3806,14 @@ int main(int argc, char *argv[]) /* prevent memory paging to swap */ mlockall(MCL_CURRENT | MCL_FUTURE); - if (argc == 8 || argc == 9) { - info("argv: %s %s %s %s %s %s %s %s", argv[0], argv[1], - argv[2], argv[3], argv[4], argv[5], argv[6], argv[7]); - } else { - fatal("wrong amount of command line parameters"); - } + print_argv(argc, argv); + + di.cmd_params = parse_args(argv, argc); + + if (di.cmd_params == NULL) + fatal("wrong parameters"); - do_all_dumps(&di, argc, argv); + do_all_dumps(&di); closelog(); munlockall(); diff --git a/src/minicoredumper/corestripper.h b/src/minicoredumper/corestripper.h index d8683e4..e1511f8 100644 --- a/src/minicoredumper/corestripper.h +++ b/src/minicoredumper/corestripper.h @@ -42,6 +42,17 @@ struct sym_data { struct sym_data *next; }; +struct cmd_parameters { + pid_t pid; + uid_t uid; + gid_t gid; + int signum; + time_t timestamp; + char *hostname; + char *cfg_path; + char *exe_name; +}; + struct dump_info { struct config *cfg; @@ -59,18 +70,13 @@ struct dump_info { struct sym_data *sym_data_list; - /* from core_pattern */ - pid_t pid; - uid_t uid; - gid_t gid; pid_t first_pid; - int signum; - time_t timestamp; - char *hostname; char *comm; /* /proc/$PID/exe */ char *exe; + /* from core_pattern */ + struct cmd_parameters *cmd_params; pid_t *tsks; int ntsks; -- 2.7.4 From m.moscicki2 at partner.samsung.com Tue May 21 14:52:39 2019 From: m.moscicki2 at partner.samsung.com (Mateusz Moscicki) Date: Tue, 21 May 2019 14:52:39 +0200 Subject: [minicoredumper] [PATCH 03/14] minicoredumper: read stack pointer from registers In-Reply-To: <1558443170-15123-1-git-send-email-m.moscicki2@partner.samsung.com> References: <1558443170-15123-1-git-send-email-m.moscicki2@partner.samsung.com> Message-ID: <1558443170-15123-4-git-send-email-m.moscicki2@partner.samsung.com> From: ?ukasz Stelmach After stopping the reporting esp/eip values in Linux kernel (0a1eb2d474ed) it is no longer possible to obtain the values of an SP register for non-crashing threads of a crashing process. This and following commits use architecture specific code to read the values from NT_PRSTATUS notes in a core dump. Change-Id: I6d5a7ef9275fc301ec11a795fb4332a7e5586c01 --- src/minicoredumper/corestripper.c | 172 +++++++++++++------------------------- src/minicoredumper/corestripper.h | 3 +- 2 files changed, 60 insertions(+), 115 deletions(-) diff --git a/src/minicoredumper/corestripper.c b/src/minicoredumper/corestripper.c index 350927f..8ebcb4b 100644 --- a/src/minicoredumper/corestripper.c +++ b/src/minicoredumper/corestripper.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -371,14 +372,11 @@ static int copy_file(const char *dest, const char *src) static int get_task_list(struct dump_info *di) { - pid_t *pidlist = NULL; struct dirent *de; int count = 0; char buf[64]; int err = 0; - int pid; DIR *d; - int i; di->tsks = NULL; di->ntsks = 0; @@ -405,51 +403,16 @@ static int get_task_list(struct dump_info *di) if (count == 0) goto out; - pidlist = calloc(count, sizeof(pid_t)); - if (!pidlist) { + di->tsks = calloc(count, sizeof(struct elf_prstatus)); + if (!di->tsks) { err = 1; goto out; } - rewinddir(d); - - /* read the actual tasks */ - for (i = 0; i < count; ) { - de = readdir(d); - if (!de) { - err = 1; - goto out; - } - - /* ignore hidden files */ - if (de->d_name[0] == '.') - continue; - - if (sscanf(de->d_name, "%d", &pid) != 1) { - err = 1; - goto out; - } - - pidlist[i] = pid; - - i++; - } - - /* make sure we really have exactly "count" tasks */ - if (readdir(d) != NULL) { - err = 1; - goto out; - } - - di->tsks = pidlist; - pidlist = NULL; di->ntsks = count; out: closedir(d); - if (pidlist) - free(pidlist); - return err; } @@ -1870,52 +1833,27 @@ static void cleanup_di(struct dump_info *di) } } -static int get_stack_pointer(pid_t pid, unsigned long *addr) +// Since the commit 0a1eb2d474ed kernel has stopped reporting eip/esp in +// /proc//stat, so we must read these values from the task memory +static void get_stack_pointer(struct dump_info *di, int i, unsigned long *addr) { -#define STAT_LINE_MAXSIZE 4096 - FILE *f = NULL; - int err = -1; - char *buf; - char *p; - int i; - - /* create a buffer large enough for stat line */ - buf = malloc(STAT_LINE_MAXSIZE); - if (!buf) - goto out_err; - - /* open stat file */ - snprintf(buf, STAT_LINE_MAXSIZE, "/proc/%d/stat", pid); - f = fopen(buf, "r"); - if (!f) - goto out_err; - - /* read line */ - if (fgets(buf, STAT_LINE_MAXSIZE, f) == NULL) - goto out_err; - - /* find 29th item: man proc(5) */ - p = buf; - for (i = 0; i < 28; i++) { - p = strchr(p, ' '); - if (!p) - goto out_err; - p++; - } - - /* read stack pointer */ - if (sscanf(p, "%lu ", addr) != 1) - goto out_err; - - err = 0; -out_err: - if (f) - fclose(f); - if (buf) - free(buf); +#if defined(__arm__) + struct user_regs *u_reg = (struct user_regs *)&di->tsks[i].pr_reg; +#else + struct user_regs_struct *u_reg = (struct user_regs_struct *)&di->tsks[i].pr_reg; +#endif - return err; -#undef STAT_LINE_MAXSIZE +#if defined(__x86_64__) + *addr = u_reg->rsp; +#elif defined(__i386__) + *addr = u_reg->esp; +#elif defined(__arm__) + *addr = u_reg->uregs[13]; +#elif defined(__aarch64__) + *addr = u_reg->sp; +#else +#error Unsupported architecture +#endif } static struct core_vma *get_next_vma_range(struct dump_info *di, @@ -1964,6 +1902,8 @@ static int dump_vma(struct dump_info *di, unsigned long start, size_t len, end = start + len; + info("dumping %p-%p", start, end); + tmp = get_next_vma_range(di, start, end, di->vma); if (!tmp) { info("vma not found start=0x%lx! bad recept or internal bug!", @@ -2002,6 +1942,12 @@ static int dump_vma(struct dump_info *di, unsigned long start, size_t len, info("dump: %s: %zu bytes @ 0x%lx", desc ? desc : "", len, dump_start); + info ("add_core_data %ld %ld %ld %p", + tmp->file_off + dump_start - tmp->start, + len, + di->mem_fd, + dump_start); + err = add_core_data(di, tmp->file_off + dump_start - tmp->start, len, di->mem_fd, dump_start); @@ -2022,6 +1968,7 @@ static int note_cb(struct dump_info *di, Elf *elf, GElf_Phdr *phdr) { size_t offset = 0; Elf_Data *data; + int i; data = elf_getdata_rawchunk(elf, phdr->p_offset, phdr->p_filesz, ELF_T_NHDR); @@ -2031,7 +1978,9 @@ static int note_cb(struct dump_info *di, Elf *elf, GElf_Phdr *phdr) return -1; } - while (offset < data->d_size) { + di->first_pid = 0; + i = 0; + while (i < di->ntsks && offset < data->d_size) { const struct elf_prstatus *status; size_t name_offset; size_t desc_offset; @@ -2053,14 +2002,14 @@ static int note_cb(struct dump_info *di, Elf *elf, GElf_Phdr *phdr) status = (const struct elf_prstatus *)desc; - di->first_pid = status->pr_pid; + if (!di->first_pid) + di->first_pid = status->pr_pid; - /* success, we can stop */ - return 1; + memcpy(&di->tsks[i], status, sizeof(struct elf_prstatus)); + i++; } - /* we found nothing, keep looking */ - return 0; + return (di->first_pid != 0); } /* @@ -2074,14 +2023,12 @@ static int dump_stacks(struct dump_info *di) size_t len; int i; - if (di->cfg->prog_config.stack.first_thread_only) { - GElf_Phdr type; + GElf_Phdr type; - /* find and set the first task */ - memset(&type, 0, sizeof(type)); - type.p_type = PT_NOTE; - do_elf_ph_parse(di, &type, note_cb); - } + /* find and set task statuses*/ + memset(&type, 0, sizeof(type)); + type.p_type = PT_NOTE; + do_elf_ph_parse(di, &type, note_cb); if (di->first_pid) info("first thread: %i", di->first_pid); @@ -2089,21 +2036,18 @@ static int dump_stacks(struct dump_info *di) for (i = 0; i < di->ntsks; i++) { /* skip this task if we should only dump the * first task and we know the first task */ - if (di->first_pid && (di->first_pid != di->tsks[i])) + if (di->cfg->prog_config.stack.first_thread_only && + di->first_pid && (di->first_pid != di->tsks[i].pr_pid)) continue; /* grab the stack pointer */ - if (get_stack_pointer(di->tsks[i], &stack_addr) != 0) { - info("unable to find thread #%d's (%d) stack pointer", - i + 1, di->tsks[i]); - continue; - } + get_stack_pointer(di, i, &stack_addr); /* find the vma containing the stack */ tmp = get_vma_pos(di, stack_addr); if (!tmp) { info("unable to find thread #%d's (%d) stack", i + 1, - di->tsks[i]); + di->tsks[i].pr_pid); continue; } @@ -2114,13 +2058,13 @@ static int dump_stacks(struct dump_info *di) max_len = di->cfg->prog_config.stack.max_stack_size; if (max_len && len > max_len) { info("stack[%d] is too large (%zu bytes), truncating " - "to %zu bytes", di->tsks[i], len, max_len); + "to %zu bytes", di->tsks[i].pr_pid, len, max_len); len = max_len; } /* dump the bottom part of stack in use */ dump_vma(di, stack_addr, len, 0, "stack[%d]", - di->tsks[i]); + di->tsks[i].pr_pid); } return 0; @@ -2844,13 +2788,13 @@ static void copy_proc_files(struct dump_info *di, int tasks, const char *name, for (i = 0 ; i < di->ntsks; i++) { snprintf(path, size, "%s/proc/%d/task/%d", di->dst_dir, - di->cmd_params->pid, di->tsks[i]); + di->cmd_params->pid, di->tsks[i].pr_pid); mkdir(path, 0700); /* handle the normal task case */ if (!do_fds) { snprintf(path, size, "%s/proc/%d/task/%d/%s", - di->dst_dir, di->cmd_params->pid, di->tsks[i], name); + di->dst_dir, di->cmd_params->pid, di->tsks[i].pr_pid, name); if (link) copy_link(path, path + base_len); @@ -2861,7 +2805,7 @@ static void copy_proc_files(struct dump_info *di, int tasks, const char *name, /* special case: copy the symlinks in the fd directory */ snprintf(path, size, "%s/proc/%d/task/%d/fd", di->dst_dir, - di->cmd_params->pid, di->tsks[i]); + di->cmd_params->pid, di->tsks[i].pr_pid); mkdir(path, 0700); d = opendir(path + base_len); @@ -2878,7 +2822,7 @@ static void copy_proc_files(struct dump_info *di, int tasks, const char *name, continue; snprintf(path, size, "%s/proc/%d/task/%d/fd/%s", - di->dst_dir, di->cmd_params->pid, di->tsks[i], + di->dst_dir, di->cmd_params->pid, di->tsks[i].pr_pid, de->d_name); copy_link(path, path + base_len); @@ -3411,10 +3355,6 @@ static void do_dump(struct dump_info *di) dump_maps(di, 1); } - /* copy intersting /proc data (if configured) */ - if (di->cfg->prog_config.write_proc_info) - write_proc_info(di); - /* Get shared object list. This is necessary for sym_address() to work. * This function will also dump the auxv data (if configured). */ get_so_list(di); @@ -3423,6 +3363,10 @@ static void do_dump(struct dump_info *di) if (di->cfg->prog_config.stack.dump_stacks) dump_stacks(di); + /* copy intersting /proc data (if configured) */ + if (di->cfg->prog_config.write_proc_info) + write_proc_info(di); + /* dump the pthread list (if configured) */ if (di->cfg->prog_config.dump_pthread_list) get_pthread_list(di); diff --git a/src/minicoredumper/corestripper.h b/src/minicoredumper/corestripper.h index 22da645..1e6c918 100644 --- a/src/minicoredumper/corestripper.h +++ b/src/minicoredumper/corestripper.h @@ -10,6 +10,7 @@ #include #include #include +#include struct core_data; @@ -80,7 +81,7 @@ struct dump_info { /* from core_pattern */ struct cmd_parameters *cmd_params; - pid_t *tsks; + struct elf_prstatus *tsks; int ntsks; unsigned long vma_start; -- 2.7.4 From m.moscicki2 at partner.samsung.com Tue May 21 14:52:41 2019 From: m.moscicki2 at partner.samsung.com (Mateusz Moscicki) Date: Tue, 21 May 2019 14:52:41 +0200 Subject: [minicoredumper] [PATCH 05/14] minicoredumper: Don't use compression if the compressor is an empty string In-Reply-To: <1558443170-15123-1-git-send-email-m.moscicki2@partner.samsung.com> References: <1558443170-15123-1-git-send-email-m.moscicki2@partner.samsung.com> Message-ID: <1558443170-15123-6-git-send-email-m.moscicki2@partner.samsung.com> Change-Id: Icf41384310aa0fc25499dcabd519268c555e70bc --- src/minicoredumper/corestripper.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/minicoredumper/corestripper.c b/src/minicoredumper/corestripper.c index 116b875..fa7a957 100644 --- a/src/minicoredumper/corestripper.c +++ b/src/minicoredumper/corestripper.c @@ -1151,7 +1151,7 @@ static int dump_compressed_tar(struct dump_info *di) if (!di->cfg->prog_config.core_in_tar) return -1; - if (!di->cfg->prog_config.core_compressor) + if (!di->cfg->prog_config.core_compressor || !di->cfg->prog_config.core_compressor[0]) return -1; buf = malloc(PAGESZ); @@ -1327,7 +1327,7 @@ static int dump_compressed_core(struct dump_info *di) char *buf; int fd; - if (!di->cfg->prog_config.core_compressor) + if (!di->cfg->prog_config.core_compressor || !di->cfg->prog_config.core_compressor[0]) return -1; buf = malloc(PAGESZ); -- 2.7.4 From m.moscicki2 at partner.samsung.com Tue May 21 14:52:40 2019 From: m.moscicki2 at partner.samsung.com (Mateusz Moscicki) Date: Tue, 21 May 2019 14:52:40 +0200 Subject: [minicoredumper] [PATCH 04/14] minicoredumper: dump NT_GNU_BUILD_ID notes In-Reply-To: <1558443170-15123-1-git-send-email-m.moscicki2@partner.samsung.com> References: <1558443170-15123-1-git-send-email-m.moscicki2@partner.samsung.com> Message-ID: <1558443170-15123-5-git-send-email-m.moscicki2@partner.samsung.com> From: Mateusz Moscicki Allow dumping of NT_GNU_BUILD_ID notes from memory mapped ELF files. This is disabled in default configuration to keep the default behaviour unchanged. Change-Id: I1d2bff4bd75a485b603cac50c62acf49199a31b2 --- etc/minicoredumper/generic.recept.json | 1 + src/minicoredumper/corestripper.c | 66 +++++++++++++++++++++++++ src/minicoredumper/minicoredumper.recept.json.5 | 3 ++ src/minicoredumper/prog_config.c | 7 +++ src/minicoredumper/prog_config.h | 1 + 5 files changed, 78 insertions(+) diff --git a/etc/minicoredumper/generic.recept.json b/etc/minicoredumper/generic.recept.json index e1c953e..15406fb 100644 --- a/etc/minicoredumper/generic.recept.json +++ b/etc/minicoredumper/generic.recept.json @@ -18,6 +18,7 @@ "dump_pthread_list": true, "dump_robust_mutex_list": true, "dump_scope": 1024, + "dump_build_id": false, "live_dumper": true, "write_proc_info": false, "write_debug_log": false, diff --git a/src/minicoredumper/corestripper.c b/src/minicoredumper/corestripper.c index 8ebcb4b..116b875 100644 --- a/src/minicoredumper/corestripper.c +++ b/src/minicoredumper/corestripper.c @@ -2100,6 +2100,64 @@ static int map_is_interesting(struct dump_info *di, const char *name, } /* + * Find end of notes + */ +bool get_notes_end_offset(int fd, size_t start, size_t *off_to_note_end) { + uint8_t *buff = (uint8_t *)malloc(sizeof(ElfW(Ehdr))); + uint8_t *header_buff = NULL; + bool result = true; + + if (!buff) { + info("allocation of %d bytes error: %s", sizeof(ElfW(Ehdr)), strerror(errno)); + result = false; + goto out; + } + + size_t tmp_ret = pread64(fd, buff, sizeof(ElfW(Ehdr)), start); + if (tmp_ret != sizeof(ElfW(Ehdr))) { + info("pread64 (len: %d addr: 0x%lx) error: %s", sizeof(ElfW(Ehdr)), start, strerror(errno)); + result = false; + goto out; + } + + if (memcmp(buff, "\x7f""ELF", 4) == 0) { + uint16_t phdr_item_size; + uint16_t phdr_item_count; + + ElfW(Ehdr) *ehdr = (ElfW(Ehdr) *)buff; + phdr_item_size = ehdr->e_phentsize; + phdr_item_count = ehdr->e_phnum; + + header_buff = (uint8_t *)malloc((size_t)(phdr_item_size*phdr_item_count)); + + tmp_ret = pread64(fd, header_buff, phdr_item_size*phdr_item_count, start+ehdr->e_phoff); + if (tmp_ret != phdr_item_size*phdr_item_count) { + info("pread64 (len: %d addr: 0x%lx) error: %s", phdr_item_size*phdr_item_count, start+ehdr->e_phoff, strerror(errno)); + result = false; + goto out; + } + + for (int i = 0; i < phdr_item_count; i++) { + ElfW(Phdr) *phdr = (ElfW(Phdr) *)(header_buff + i*phdr_item_size); + if (phdr->p_type == PT_NOTE) { + *off_to_note_end = phdr->p_offset + phdr->p_memsz; + goto out; + } + } + result = false; + } else { + *off_to_note_end = 0; + result = false; + } + +out: + free(header_buff); + free(buff); + + return result; +} + +/* * Iterates over all maps and dumps the selected ones. */ static int dump_maps(struct dump_info *di, int get_only) @@ -2143,6 +2201,14 @@ static int dump_maps(struct dump_info *di, int get_only) if (perms[0] != 'r') continue; + /* dump build id */ + if (di->cfg->prog_config.dump_build_id) { + size_t off_to_note_end = 0; + if (get_notes_end_offset(di->mem_fd, start, &off_to_note_end)) { + dump_vma(di, start, off_to_note_end, 0, "notes"); + } + } + if (get_only) { add_vma(di, start, end, end, start, 0); continue; diff --git a/src/minicoredumper/minicoredumper.recept.json.5 b/src/minicoredumper/minicoredumper.recept.json.5 index 78459b3..4bac92b 100644 --- a/src/minicoredumper/minicoredumper.recept.json.5 +++ b/src/minicoredumper/minicoredumper.recept.json.5 @@ -66,6 +66,9 @@ to identify mutex attributes and states in shared memory. .B dump_scope (integer) Only registered dumps at or below this value will be dumped. .TP +.B dump_build_id +(boolean) Dump GNU_BUILD_ID note +.TP .B live_dumper (boolean) Whether the .BR minicoredumper (1) diff --git a/src/minicoredumper/prog_config.c b/src/minicoredumper/prog_config.c index 88721d5..0cd195b 100644 --- a/src/minicoredumper/prog_config.c +++ b/src/minicoredumper/prog_config.c @@ -364,6 +364,10 @@ static int read_prog_config(struct json_object *root, struct prog_config *cfg) if (read_prog_compression_config(v, cfg) != 0) return -1; + } else if (strcmp(n, "dump_build_id") == 0) { + if (get_json_boolean(v, &cfg->dump_build_id) != 0) + return -1; + } else if (strcmp(n, "dump_robust_mutex_list") == 0) { if (get_json_boolean(v, &cfg->dump_robust_mutex_list) != 0) { @@ -687,6 +691,9 @@ static void set_config_defaults(struct prog_config *cfg) /* for compression, pack in tarball */ cfg->core_in_tar = true; + + /* dump NT_GNU_BUILD_ID */ + cfg->dump_build_id = false; } int init_prog_config(struct config *cfg, const char *cfg_file) diff --git a/src/minicoredumper/prog_config.h b/src/minicoredumper/prog_config.h index fcd11b8..5d77f2d 100644 --- a/src/minicoredumper/prog_config.h +++ b/src/minicoredumper/prog_config.h @@ -45,6 +45,7 @@ struct prog_config { char *core_compressor_ext; bool core_in_tar; bool core_compressed; + bool dump_build_id; bool dump_fat_core; bool dump_auxv_so_list; bool dump_pthread_list; -- 2.7.4 From m.moscicki2 at partner.samsung.com Tue May 21 14:52:44 2019 From: m.moscicki2 at partner.samsung.com (Mateusz Moscicki) Date: Tue, 21 May 2019 14:52:44 +0200 Subject: [minicoredumper] [PATCH 08/14] minicoredumper: Log errors for copy_link() and copy_file() In-Reply-To: <1558443170-15123-1-git-send-email-m.moscicki2@partner.samsung.com> References: <1558443170-15123-1-git-send-email-m.moscicki2@partner.samsung.com> Message-ID: <1558443170-15123-9-git-send-email-m.moscicki2@partner.samsung.com> Change-Id: Id7eedf29e02911e3caf3e6a265149a44ea283219 --- src/minicoredumper/corestripper.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/minicoredumper/corestripper.c b/src/minicoredumper/corestripper.c index 27fe8c0..74141ce 100644 --- a/src/minicoredumper/corestripper.c +++ b/src/minicoredumper/corestripper.c @@ -336,8 +336,10 @@ static int copy_file(const char *dest, const char *src) int i; f_src = fopen(src, "r"); - if (!f_src) + if (!f_src) { + info("Failed to open a file %s for reading: %m", src); return -1; + } if (fstat(fileno(f_src), &sb) != 0) { fclose(f_src); @@ -353,6 +355,7 @@ static int copy_file(const char *dest, const char *src) f_dest = fopen(dest, "w"); if (!f_dest) { fclose(f_src); + info("Failed to open a file %s for writing: %m", dest); return -1; } @@ -2821,8 +2824,10 @@ static int copy_link(const char *dest, const char *src) char *linkname; int ret; - if (lstat(src, &sb) != 0) + if (lstat(src, &sb) != 0) { + info("Failed to lstat() for %s: %m", src); return -1; + } /* stat/lstat is screwy for /proc/.../cwd, so * fallback to stat if lstat provides no size */ @@ -2843,6 +2848,7 @@ static int copy_link(const char *dest, const char *src) if (ret < 2) { /* empty link? */ free(linkname); + info("Failed to readlink() for %s: %m", src); return -1; } /* truncate when too long */ -- 2.7.4 From m.moscicki2 at partner.samsung.com Tue May 21 14:52:42 2019 From: m.moscicki2 at partner.samsung.com (Mateusz Moscicki) Date: Tue, 21 May 2019 14:52:42 +0200 Subject: [minicoredumper] [PATCH 06/14] minicoredumper: Add checking if the mapped memory regions are in the coredump In-Reply-To: <1558443170-15123-1-git-send-email-m.moscicki2@partner.samsung.com> References: <1558443170-15123-1-git-send-email-m.moscicki2@partner.samsung.com> Message-ID: <1558443170-15123-7-git-send-email-m.moscicki2@partner.samsung.com> Minicoredumper try to dump NT_GNU_BUILD_ID notes for the every mapped shared object. In some cases (e.g. on armv7l) the different memory regions are mapped at the same file offset: ... 0xb6f78000 0xb6f7f000 0x00000000 /usr/bin/dotnet-launcher 0xb6f8e000 0xb6f8f000 0x00000006 /usr/bin/dotnet-launcher ... Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align ... LOAD 0x80b7000 0xb6f78000 0x00000000 0x00000 0x07000 R E 0x1000 LOAD 0x80b7000 0xb6f8e000 0x00000000 0x01000 0x01000 RW 0x1000 ... We have to check if the region with NT_GNU_BUILD_ID exists in the coredump file. Otherwise data in RW region will be overwritten and it can cause that it will be impossible to unwind call stack. Change-Id: I22247c24c7f524a1cd44abc5fb5d38364de43636 --- src/minicoredumper/corestripper.c | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/minicoredumper/corestripper.c b/src/minicoredumper/corestripper.c index fa7a957..65df340 100644 --- a/src/minicoredumper/corestripper.c +++ b/src/minicoredumper/corestripper.c @@ -2157,6 +2157,29 @@ out: return result; } +static struct core_vma* find_vma(struct dump_info *di, size_t start) +{ + struct core_vma* res = NULL; + for (struct core_vma* p = di->vma; p != NULL; p = p->next) { + if (p->start == start) { + res = p; + break; + } + } + return res; +} + +static off64_t vma_in_file_len(struct dump_info *di, size_t start) +{ + struct core_vma* vma = find_vma(di, start); + if (vma == NULL) { + info("vma on 0x%lx not found", start); + return -1; + } + + return vma->file_end - vma->start; +} + /* * Iterates over all maps and dumps the selected ones. */ @@ -2204,9 +2227,8 @@ static int dump_maps(struct dump_info *di, int get_only) /* dump build id */ if (di->cfg->prog_config.dump_build_id) { size_t off_to_note_end = 0; - if (get_notes_end_offset(di->mem_fd, start, &off_to_note_end)) { + if ((vma_in_file_len(di, start) > 0) && get_notes_end_offset(di->mem_fd, start, &off_to_note_end)) dump_vma(di, start, off_to_note_end, 0, "notes"); - } } if (get_only) { -- 2.7.4 From m.moscicki2 at partner.samsung.com Tue May 21 14:52:45 2019 From: m.moscicki2 at partner.samsung.com (Mateusz Moscicki) Date: Tue, 21 May 2019 14:52:45 +0200 Subject: [minicoredumper] [PATCH 09/14] minicoredumper: Write an uncompressed core and a fatcore as a sparse file In-Reply-To: <1558443170-15123-1-git-send-email-m.moscicki2@partner.samsung.com> References: <1558443170-15123-1-git-send-email-m.moscicki2@partner.samsung.com> Message-ID: <1558443170-15123-10-git-send-email-m.moscicki2@partner.samsung.com> The uncompressed core and fatcore may contain large empty areas. In this case we can write a sparse file to save disk space. Change-Id: Ib0bfee740bba89dc4d6b97084b775480ba541e39 --- src/minicoredumper/corestripper.c | 47 +++++++++++++++++++++++++++++++++++---- 1 file changed, 43 insertions(+), 4 deletions(-) diff --git a/src/minicoredumper/corestripper.c b/src/minicoredumper/corestripper.c index 74141ce..ed2fd97 100644 --- a/src/minicoredumper/corestripper.c +++ b/src/minicoredumper/corestripper.c @@ -127,10 +127,10 @@ static ssize_t read_file_fd(int fd, char *dst, int len) return size; } -static ssize_t write_file_fd(int fd, char *src, int len) +static ssize_t write_file_fd(int fd, char *src, size_t len) { size_t size = 0; - int r; + ssize_t r; do { r = write(fd, src + size, len); @@ -147,6 +147,34 @@ static ssize_t write_file_fd(int fd, char *src, int len) return size; } +static bool is_empty_region(char *src, size_t len) { + for (size_t i = 0; i < len; i++) { + if (src[i] != 0) + return false; + } + return true; +} + +static ssize_t write_sparse_file_fd(int fd, char *src, size_t len) +{ + ssize_t ret = -1; + + if (is_empty_region(src, len)) { + if (lseek64(fd, len, SEEK_CUR) != -1) { + if (len > SSIZE_MAX) + ret = SSIZE_MAX; + else + ret = len; + } else { + info("lseek64 error (len = %d): %m", len); + } + } + if (ret < 0) + ret = write_file_fd(fd, src, len); + + return ret; +} + static void check_config(struct config *cfg) { if (!cfg->base_dir) @@ -881,6 +909,15 @@ static int parse_vma_info(struct dump_info *di) return 0; } +static bool is_file(int fd) { + struct stat buf; + if (fstat(fd, &buf) == -1) { + info("fstat error: %m"); + return false; + } + return S_ISREG(buf.st_mode); +} + /* * Copy data from a source core to (optionally) multiple destination cores. * Assumes all files are already positioned correctly to begin. @@ -889,6 +926,8 @@ static int copy_data(int src, int dest, int dest2, size_t len, char *pagebuf) { size_t chunk; int ret; + ssize_t (*const write_func)(int fd, char *src, size_t len) = + is_file(dest) ? write_sparse_file_fd : write_file_fd; if (len < (size_t)PAGESZ) chunk = len; @@ -906,7 +945,7 @@ static int copy_data(int src, int dest, int dest2, size_t len, char *pagebuf) return -1; } - ret = write_file_fd(dest, pagebuf, chunk); + ret = write_func(dest, pagebuf, chunk); if (ret < 0) { info("write core failed at 0x%lx", lseek64(dest, 0, SEEK_CUR)); @@ -914,7 +953,7 @@ static int copy_data(int src, int dest, int dest2, size_t len, char *pagebuf) } if (dest2 >= 0) { - ret = write_file_fd(dest2, pagebuf, chunk); + ret = write_func(dest2, pagebuf, chunk); if (ret < 0) { info("write core2 failed at 0x%lx", lseek64(dest2, 0, SEEK_CUR)); -- 2.7.4 From m.moscicki2 at partner.samsung.com Tue May 21 14:52:43 2019 From: m.moscicki2 at partner.samsung.com (Mateusz Moscicki) Date: Tue, 21 May 2019 14:52:43 +0200 Subject: [minicoredumper] [PATCH 07/14] minicoredumper: Fix Coverity and SVACE warnings In-Reply-To: <1558443170-15123-1-git-send-email-m.moscicki2@partner.samsung.com> References: <1558443170-15123-1-git-send-email-m.moscicki2@partner.samsung.com> Message-ID: <1558443170-15123-8-git-send-email-m.moscicki2@partner.samsung.com> Change-Id: Ib9164189283e72c6b3a37b7855f86990e3d686ee --- src/common/elf_dumplist.c | 16 ++- src/minicoredumper/corestripper.c | 212 ++++++++++++++++++++++++-------------- src/minicoredumper/prog_config.c | 24 +++-- 3 files changed, 155 insertions(+), 97 deletions(-) diff --git a/src/common/elf_dumplist.c b/src/common/elf_dumplist.c index e293e62..f76ba8c 100644 --- a/src/common/elf_dumplist.c +++ b/src/common/elf_dumplist.c @@ -309,7 +309,7 @@ static int alloc_dump_note(struct core_data *dump_list, int elfclass, n->n_type = NT_DUMPLIST; n->n_namesz = name_size; n->n_descsz = desc_size; - sprintf(NOTE_NAME_PTR(n), NT_OWNER); + snprintf(NOTE_NAME_PTR(n), name_size, NT_OWNER); desc = NOTE_DESC_PTR(n, name_size); for (cur = dump_list; cur; cur = cur->next) { @@ -356,7 +356,7 @@ static void _prune_dump_list(int elfclass, void *desc, int count, } } -static int prune_dump_list(int elfclass, Elf_Data *data, +static void prune_dump_list(int elfclass, Elf_Data *data, struct core_data *dump_list) { char *name; @@ -385,8 +385,6 @@ static int prune_dump_list(int elfclass, Elf_Data *data, n = ((void *)n) + nsize; } - - return 0; } int add_dump_list(int core_fd, size_t *core_size, @@ -466,7 +464,7 @@ int add_dump_list(int core_fd, size_t *core_size, * directly after the elf header) */ if (offset == ehdr.e_phoff) - offset += ehdr.e_phentsize * ehdr.e_phnum; + offset += (GElf_Off)(ehdr.e_phentsize * ehdr.e_phnum); if (add_debug_section(e, strtab_scn, offset, last_offset - offset) != 0) { @@ -499,10 +497,8 @@ int add_dump_list(int core_fd, size_t *core_size, /* disable dump list items that are already * covered by the existing data */ - if (prune_dump_list(gelf_getclass(e), data, - dump_list) != 0) { - goto out; - } + prune_dump_list(gelf_getclass(e), data, + dump_list); } } else { /* create new section */ @@ -562,7 +558,7 @@ int add_dump_list(int core_fd, size_t *core_size, if (gelf_getehdr(e, &ehdr) == NULL) goto out; - *core_size = last_offset + (ehdr.e_shentsize * ehdr.e_shnum); + *core_size = last_offset + (GElf_Off)(ehdr.e_shentsize * ehdr.e_shnum); err = 0; out: diff --git a/src/minicoredumper/corestripper.c b/src/minicoredumper/corestripper.c index 65df340..27fe8c0 100644 --- a/src/minicoredumper/corestripper.c +++ b/src/minicoredumper/corestripper.c @@ -114,8 +114,7 @@ static ssize_t read_file_fd(int fd, char *dst, int len) do { r = read(fd, dst + size, len); if (r == -1) { - info("Couldn't read file fd=%d; error %s", fd, - strerror(errno)); + info("Couldn't read file fd=%d; error %m", fd); return r; } @@ -136,8 +135,7 @@ static ssize_t write_file_fd(int fd, char *src, int len) do { r = write(fd, src + size, len); if (r == -1) { - info("Couldn't write file fd=%d error %s", fd, - strerror (errno)); + info("Couldn't write file fd=%d error %m", fd); return r; } if (r > 0) { @@ -337,16 +335,20 @@ static int copy_file(const char *dest, const char *src) FILE *f_src; int i; - if (stat(src, &sb) != 0) + f_src = fopen(src, "r"); + if (!f_src) return -1; - /* non-regular files ignored */ - if ((sb.st_mode & S_IFMT) != S_IFREG) + if (fstat(fileno(f_src), &sb) != 0) { + fclose(f_src); return -1; + } - f_src = fopen(src, "r"); - if (!f_src) + /* non-regular files ignored */ + if ((sb.st_mode & S_IFMT) != S_IFREG) { + fclose(f_src); return -1; + } f_dest = fopen(dest, "w"); if (!f_dest) { @@ -531,8 +533,7 @@ static char *alloc_dst_dir(time_t timestamp, const char *base_dir, } if (mkdir(tmp_path, 0700) == -1) { - info("unable to create directory \'%s\': %s", tmp_path, - strerror(errno)); + info("unable to create directory \'%s\': %m", tmp_path); free(tmp_path); return NULL; } @@ -607,8 +608,7 @@ static int init_di(struct dump_info *di) di->elf_fd = shm_open(tmp_path, O_CREAT|O_EXCL|O_RDWR, S_IRUSR|S_IWUSR); if (di->elf_fd < 0) { - info("unable to create shared object \'%s\': %s", tmp_path, - strerror(errno)); + info("unable to create shared object \'%s\': %m", tmp_path); free(tmp_path); return 1; } @@ -621,8 +621,7 @@ static int init_di(struct dump_info *di) di->core_fd = open(di->core_path, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR); if (di->core_fd < 0) { - info("unable to create core \'%s\': %s", di->core_path, - strerror(errno)); + info("unable to create core \'%s\': %m", di->core_path); return 1; } } else { @@ -642,8 +641,7 @@ static int init_di(struct dump_info *di) di->fatcore_fd = open(tmp_path, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR); if (di->fatcore_fd < 0) { - info("unable to create fatcore \'%s\': %s", tmp_path, - strerror(errno)); + info("unable to create fatcore \'%s\': %m", tmp_path); free(tmp_path); return 1; } @@ -656,8 +654,7 @@ static int init_di(struct dump_info *di) di->mem_fd = open(tmp_path, O_RDONLY); if (di->mem_fd < 0) { - info("unable to open mem \'%s\': %s", tmp_path, - strerror(errno)); + info("unable to open mem \'%s\': %m", tmp_path); free(tmp_path); return 1; } @@ -679,7 +676,7 @@ static int init_log(struct dump_info *di) di->info_file = fopen(tmp_path, "w+"); if (di->info_file == NULL) { - info("unable to create \'%s\': %s", tmp_path, strerror(errno)); + info("unable to create \'%s\': %m", tmp_path); free(tmp_path); return 1; } @@ -709,7 +706,7 @@ static int do_elf_ph_parse(struct dump_info *di, GElf_Phdr *type, /* start from beginning of core */ if (lseek64(di->elf_fd, 0, SEEK_SET) == -1) { - info("lseek failed: %s", strerror(errno)); + info("lseek failed: %m"); goto out; } @@ -1094,6 +1091,7 @@ static int open_compressor(struct dump_info *di, const char *core_suffix, if (pipe(pipefd) != 0) { free(tmp_path); + close(fd); return -1; } @@ -1102,6 +1100,7 @@ static int open_compressor(struct dump_info *di, const char *core_suffix, close(pipefd[0]); close(pipefd[1]); free(tmp_path); + close(fd); return -1; } @@ -2108,14 +2107,14 @@ bool get_notes_end_offset(int fd, size_t start, size_t *off_to_note_end) { bool result = true; if (!buff) { - info("allocation of %d bytes error: %s", sizeof(ElfW(Ehdr)), strerror(errno)); + info("allocation of %d bytes error: %m", sizeof(ElfW(Ehdr))); result = false; goto out; } size_t tmp_ret = pread64(fd, buff, sizeof(ElfW(Ehdr)), start); if (tmp_ret != sizeof(ElfW(Ehdr))) { - info("pread64 (len: %d addr: 0x%lx) error: %s", sizeof(ElfW(Ehdr)), start, strerror(errno)); + info("pread64 (len: %d addr: 0x%lx) error: %m", sizeof(ElfW(Ehdr)), start); result = false; goto out; } @@ -2132,7 +2131,7 @@ bool get_notes_end_offset(int fd, size_t start, size_t *off_to_note_end) { tmp_ret = pread64(fd, header_buff, phdr_item_size*phdr_item_count, start+ehdr->e_phoff); if (tmp_ret != phdr_item_size*phdr_item_count) { - info("pread64 (len: %d addr: 0x%lx) error: %s", phdr_item_size*phdr_item_count, start+ehdr->e_phoff, strerror(errno)); + info("pread64 (len: %d addr: 0x%lx) error: %m", phdr_item_size*phdr_item_count, start+ehdr->e_phoff); result = false; goto out; } @@ -2209,7 +2208,11 @@ static int dump_maps(struct dump_info *di, int get_only) while (fgets(buf, MAPS_LINE_MAXSIZE, f)) { /* read memory range */ - if (sscanf(buf, "%lx-%lx ", &start, &end) != 2) + start = strtoul(buf, &p, 16); + if (p == buf || p >= (buf + strlen(buf))) + continue; + end = strtoul(p+1, &p, 16); + if (p == buf) continue; /* find 2nd item: man proc(5) */ @@ -2268,23 +2271,22 @@ static int dump_maps(struct dump_info *di, int get_only) out_err: if (f) fclose(f); - if (buf) - free(buf); + free(buf); return err; #undef MAPS_LINE_MAXSIZE } static int read_remote(struct dump_info *di, unsigned long addr, void *dst, - ssize_t len) + size_t len) { int ret; ret = pread64(di->mem_fd, dst, len, addr); if (ret != len) { - info("read_remote failed: len=%d, addr=0x%lx, " - "dest=0x%x, errno=\"%s\"", - len, addr, dst, strerror(errno)); + info("read_remote failed: len=%zu, addr=0x%lx, " + "dest=0x%x, errno=\"%m\"", + len, addr, dst); return -1; } @@ -2314,8 +2316,7 @@ static int alloc_remote_string(struct dump_info *di, unsigned long addr, ret = pread64(di->mem_fd, ptr, i, addr); if (ret != i) { ret = errno; - info("read_remote failed: addr %#lx: %s", addr, - strerror(errno)); + info("read_remote failed: addr %#lx: %m", addr); free(ptr); if (ret == 0) ret = -1; @@ -2424,6 +2425,9 @@ static int alloc_remote_data_content(struct dump_info *di, unsigned long addr, return 0; } + if (dd->es_n > SIZE_MAX / sizeof(*es)) + return EFAULT; + es = calloc(sizeof(*es), dd->es_n); if (!es) { /* clear fields so there is no free() attempt */ @@ -2455,7 +2459,7 @@ static int dump_data_to_core(struct dump_info *di, struct dump_data_elem *es, if ((es->flags & MCD_DATA_PTR_INDIRECT)) { addr_ind = (unsigned long)es->data_ptr; ret = read_remote(di, (unsigned long)es->data_ptr, - &addr, sizeof(es->data_ptr)); + &addr, sizeof(addr)); if (ret != 0) return ret; } else { @@ -2466,7 +2470,7 @@ static int dump_data_to_core(struct dump_info *di, struct dump_data_elem *es, /* resolve length pointer */ if ((es->flags & MCD_LENGTH_INDIRECT)) { ret = read_remote(di, (unsigned long)es->u.length_ptr, - &length, sizeof(es->u.length_ptr)); + &length, sizeof(length)); if (ret != 0) return ret; } else { @@ -2554,7 +2558,7 @@ static int dump_data_file_bin(struct dump_info *di, struct mcd_dump_data *dd, if ((es->flags & MCD_DATA_PTR_INDIRECT)) { addr_ind = (unsigned long)es->data_ptr; ret = read_remote(di, (unsigned long)es->data_ptr, - &addr, sizeof(es->data_ptr)); + &addr, sizeof(addr)); if (ret != 0) return ret; } else { @@ -2565,7 +2569,7 @@ static int dump_data_file_bin(struct dump_info *di, struct mcd_dump_data *dd, /* resolve length pointer */ if ((es->flags & MCD_LENGTH_INDIRECT)) { ret = read_remote(di, (unsigned long)es->u.length_ptr, - &length, sizeof(es->u.length_ptr)); + &length, sizeof(length)); if (ret != 0) return ret; } else { @@ -2615,6 +2619,15 @@ out: return ret; } +static bool make_dir(const char *path) { + if (mkdir(path, 0700) == 0 || errno == EEXIST) { + return true; + } else { + info("mkdir %s failed: %m\n", path); + return false; + } +} + static int dump_data_content_file(struct dump_info *di, struct mcd_dump_data *dd) { @@ -2632,11 +2645,13 @@ static int dump_data_content_file(struct dump_info *di, /* create "dumps" directory */ snprintf(tmp_path, len, "%s/dumps", di->dst_dir); - mkdir(tmp_path, 0700); + if (!make_dir(tmp_path)) + goto out; /* create dumps pid sub-directory */ snprintf(tmp_path, len, "%s/dumps/%i", di->dst_dir, di->cmd_params->pid); - mkdir(tmp_path, 0700); + if (!make_dir(tmp_path)) + goto out; /* open text file for output */ snprintf(tmp_path, len, "%s/dumps/%i/%s", di->dst_dir, di->cmd_params->pid, @@ -2663,9 +2678,14 @@ static int dump_data_content_file(struct dump_info *di, fclose(file); /* delete file if it is empty */ - if (stat(tmp_path, &sb) == 0) { - if (sb.st_size == 0) + int tmp_fd = open(tmp_path, 0); + + if (tmp_fd == -1) + info("Cannot open file %s: %m\n", tmp_path); + else { + if (fstat(tmp_fd, &sb) == 0 && sb.st_size == 0) unlink(tmp_path); + close(tmp_fd); } out: free(tmp_path); @@ -2777,13 +2797,21 @@ static void dump_fat_core(struct dump_info *di) for (tmp = di->vma; tmp; tmp = tmp->next) { len = tmp->file_end - tmp->start; - lseek64(di->mem_fd, tmp->start, SEEK_SET); - lseek64(di->fatcore_fd, tmp->file_off, SEEK_SET); + if (lseek64(di->mem_fd, tmp->start, SEEK_SET) == -1) { + info("lseek64 error: %m"); + goto out; + } + if (lseek64(di->fatcore_fd, tmp->file_off, SEEK_SET) == -1) { + info("lseek64 error: %m"); + goto out; + } if (copy_data(di->mem_fd, di->fatcore_fd, -1, len, buf) < 0) break; } +out: + free(buf); } @@ -2855,9 +2883,11 @@ static void copy_proc_files(struct dump_info *di, int tasks, const char *name, do_fds = 1; snprintf(path, size, "%s/proc", di->dst_dir); - mkdir(path, 0700); + if (!make_dir(path)) + goto out; snprintf(path, size, "%s/proc/%d", di->dst_dir, di->cmd_params->pid); - mkdir(path, 0700); + if (!make_dir(path)) + goto out; /* handle non-task file */ if (!tasks) { @@ -2867,17 +2897,18 @@ static void copy_proc_files(struct dump_info *di, int tasks, const char *name, copy_link(path, path + base_len); else copy_file(path, path + base_len); - free(path); - return; + goto out; } snprintf(path, size, "%s/proc/%d/task", di->dst_dir, di->cmd_params->pid); - mkdir(path, 0700); + if (!make_dir(path)) + goto out; for (i = 0 ; i < di->ntsks; i++) { snprintf(path, size, "%s/proc/%d/task/%d", di->dst_dir, di->cmd_params->pid, di->tsks[i].pr_pid); - mkdir(path, 0700); + if (!make_dir(path)) + continue; /* handle the normal task case */ if (!do_fds) { @@ -2894,7 +2925,8 @@ static void copy_proc_files(struct dump_info *di, int tasks, const char *name, /* special case: copy the symlinks in the fd directory */ snprintf(path, size, "%s/proc/%d/task/%d/fd", di->dst_dir, di->cmd_params->pid, di->tsks[i].pr_pid); - mkdir(path, 0700); + if (!make_dir(path)) + continue; d = opendir(path + base_len); if (!d) @@ -2918,7 +2950,7 @@ static void copy_proc_files(struct dump_info *di, int tasks, const char *name, closedir(d); } - +out: free(path); } @@ -3252,6 +3284,7 @@ static int get_so_list(struct dump_info *di) void *buf; int ret; int fd; + int result = 0; if (asprintf(&filename, "/proc/%d/auxv", di->cmd_params->pid) == -1) return -1; @@ -3271,18 +3304,22 @@ static int get_so_list(struct dump_info *di) close(fd); - if (ret < 0) - return -1; + if (ret < 0) { + info("/proc/%d/auxv read error: %m", di->cmd_params->pid); + result = -1; + goto out; + } /* get value from DT_DEBUG element from /proc/PID/auxv * (this is the r_debug structure) */ - if (init_from_auxv(di, buf, &ptr) != 0) - return -1; - - free(buf); + if ((ret = init_from_auxv(di, buf, &ptr)) != 0) { + info("init_from_auxv error: %d", ret); + result = -1; + goto out; + } if (!ptr) - return 0; + goto out; /* dump r_debug structure */ if (di->cfg->prog_config.dump_auxv_so_list) @@ -3332,7 +3369,10 @@ static int get_so_list(struct dump_info *di) &ptr, sizeof(ptr)); } - return 0; +out: + free(buf); + + return result; } static void get_interesting_buffers(struct dump_info *di) @@ -3343,7 +3383,7 @@ static void get_interesting_buffers(struct dump_info *di) unsigned long addr; int ret; - memset(&dd, 0, sizeof(es)); + memset(&dd, 0, sizeof(dd)); dd.es_n = 1; dd.es = &es; dd.type = MCD_BIN; @@ -3445,7 +3485,8 @@ static void do_dump(struct dump_info *di) /* Get shared object list. This is necessary for sym_address() to work. * This function will also dump the auxv data (if configured). */ - get_so_list(di); + if (get_so_list(di) < 0) + fatal("get_so_list failed"); /* dump all stacks (if configured) */ if (di->cfg->prog_config.stack.dump_stacks) @@ -3621,16 +3662,19 @@ static struct cmd_parameters* copy_cmd_params(struct cmd_parameters* cmd_params) static int do_all_dumps(struct dump_info *di) { - struct config *cfg = NULL; - const char *recept; + struct config* cfg = NULL; + const char *recept = NULL; + int result = 1; bool live_dumper; - char *comm_base; - char *comm; - char *exe; + char *comm_base = NULL; + char *comm = NULL; + char *exe = NULL; char *p; struct cmd_parameters *orig_params, *ext_params; + di->dst_dir = NULL; + ext_params = copy_cmd_params(di->cmd_params); if (ext_params == NULL) fatal("malloc for ext_params error: %m"); @@ -3647,7 +3691,7 @@ static int do_all_dumps(struct dump_info *di) comm = alloc_comm(di->cmd_params->exe_name, di->cmd_params->pid); if (!comm) - return 1; + goto out; if (di->cmd_params->pid == 0) exe = strdup(""); @@ -3655,7 +3699,7 @@ static int do_all_dumps(struct dump_info *di) exe = alloc_exe(di->cmd_params->pid); if (!exe) - return 1; + goto out; comm_base = comm; while (1) { @@ -3673,20 +3717,17 @@ static int do_all_dumps(struct dump_info *di) } if (!di->dst_dir) - return 1; + goto out; recept = get_prog_recept(cfg, comm, exe); if (!recept) - return 1; + goto out; if (init_prog_config(cfg, recept) != 0) - return 1; + goto out; live_dumper = cfg->prog_config.live_dumper; - free_config(cfg); - free(comm); - free(exe); if (live_dumper) { char pidstr[16]; @@ -3740,16 +3781,23 @@ static int do_all_dumps(struct dump_info *di) free(pids); } - free(ext_params); if (di->cmd_params->pid != 0) { /* dump crashed task */ do_dump(di); } + result = 0; +out: + + free_config(cfg); + free(comm); + free(exe); + + free(ext_params); free(di->dst_dir); - return 0; + return result; } typedef enum { @@ -3837,15 +3885,18 @@ struct cmd_parameters* parse_args(char *argv[], int argc) return cmd_params; } +#define BUFF_LEN 1024 + void print_argv(int argc, char *argv[]) { - char buff[1024]; + char buff[BUFF_LEN]; int offset = 0; for (int i = 0; i < argc; i++) { - int ret = snprintf(&buff[offset], 1024-offset, " %s", argv[i]); + int ret = snprintf(&buff[offset], BUFF_LEN-offset, " %s", argv[i]); if (ret < 0) fatal("print command line arguments error"); - offset += ret; + else + offset += ret; } info("argv:%s", buff); } @@ -3869,7 +3920,8 @@ int main(int argc, char *argv[]) openlog("minicoredumper", LOG_NDELAY, LOG_SYSLOG); /* prevent memory paging to swap */ - mlockall(MCL_CURRENT | MCL_FUTURE); + if (mlockall(MCL_CURRENT | MCL_FUTURE) != 0) + info("mlockall failed: %m"); print_argv(argc, argv); diff --git a/src/minicoredumper/prog_config.c b/src/minicoredumper/prog_config.c index 0cd195b..a9b8b09 100644 --- a/src/minicoredumper/prog_config.c +++ b/src/minicoredumper/prog_config.c @@ -214,21 +214,25 @@ static int read_buffer_item(struct json_object *root, struct prog_config *cfg) goto out_err; if (strcmp(n, "symname") == 0) { + if (tmp->symname) + free(tmp->symname); tmp->symname = alloc_json_string(v); if (!tmp->symname) goto out_err; } else if (strcmp(n, "follow_ptr") == 0) { if (get_json_boolean(v, &tmp->follow_ptr) != 0) - return -1; + goto out_err; } else if (strcmp(n, "data_len") == 0) { int i; if (get_json_int(v, &i, true) != 0) - return -1; + goto out_err; tmp->data_len = i; } else if (strcmp(n, "ident") == 0) { + if (tmp->ident) + free(tmp->ident); tmp->ident = alloc_json_string(v); if (!tmp->ident) goto out_err; @@ -515,11 +519,15 @@ static int read_watch_elem(struct json_object *root, struct config *cfg) goto out_err; if (strcmp(n, "exe") == 0) { + if (tmp->exe) + free(tmp->exe); tmp->exe = alloc_json_string(v); if (!tmp->exe) goto out_err; } else if (strcmp(n, "comm") == 0) { + if (tmp->comm) + free(tmp->comm); tmp->comm = alloc_json_string(v); if (!tmp->comm) goto out_err; @@ -532,6 +540,8 @@ static int read_watch_elem(struct json_object *root, struct config *cfg) goto out_err; if (s[0] == '/') { + if (tmp->recept) + free(tmp->recept); /* absolute path */ tmp->recept = s; } else { @@ -628,6 +638,8 @@ static int read_base_config(struct json_object *root, struct config *cfg) } } else if (strcmp(n, "base_dir") == 0) { + if (cfg->base_dir) + free(cfg->base_dir); cfg->base_dir = alloc_json_string(v); if (!cfg->base_dir) return -1; @@ -650,15 +662,14 @@ struct config *init_config(const char *cfg_file) return NULL; o = json_object_from_file(cfg_file); if (!o) { - fatal("unable to parse config file: %s", strerror(errno)); free(cfg); - return NULL; + fatal("unable to parse config file: %s", strerror(errno)); } if (read_base_config(o, cfg) < 0) { - fatal("unable to read base config"); - free(cfg); + free_config(cfg); cfg = NULL; + fatal("unable to read base config"); } json_object_put(o); @@ -710,7 +721,6 @@ int init_prog_config(struct config *cfg, const char *cfg_file) o = json_object_from_file(cfg_file); if (!o) { fatal("unable to parse recept file: %s", strerror(errno)); - return -1; } ret = read_prog_config(o, &cfg->prog_config); -- 2.7.4 From m.moscicki2 at partner.samsung.com Tue May 21 14:52:47 2019 From: m.moscicki2 at partner.samsung.com (Mateusz Moscicki) Date: Tue, 21 May 2019 14:52:47 +0200 Subject: [minicoredumper] [PATCH 11/14] minicoredumper: Fix checking if memory regions can be merged In-Reply-To: <1558443170-15123-1-git-send-email-m.moscicki2@partner.samsung.com> References: <1558443170-15123-1-git-send-email-m.moscicki2@partner.samsung.com> Message-ID: <1558443170-15123-12-git-send-email-m.moscicki2@partner.samsung.com> By default the coredump doesn't contain a file-backed private or shared mappings, so it is sometimes impossible to merge two theoretically neighboring regions. In this case: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align [...] LOAD 0x4f77000 0xb2a94000 0x00000000 0x0a000 0x0a000 RW 0x1000 LOAD 0x4f81000 0xb2a9e000 0x00000000 0x01000 0x01000 RWE 0x1000 [A] LOAD 0x4f82000 0xb2a9f000 0x00000000 0x00000 0x02000 0x1000 LOAD 0x4f82000 0xb2aa1000 0x00000000 0x03000 0x03000 RW 0x1000 [B] LOAD 0x4f85000 0xb2aa4000 0x00000000 0x01000 0x01000 RWE 0x1000 LOAD 0x4f86000 0xb2aa5000 0x00000000 0x00000 0x02000 0x1000 [...] we can not merge regions A and B by simply expanding the region A, because the final minicoredump will contain memory region 0xb2a9e000-0xb2aa2000 at offset 0x4f81000 instead of 0xb2a9e000-0xb2a9f000 at offset 0x4f81000 and 0xb2aa1000-0xb2aa4000 at offset 0x4f82000 Change-Id: I550446b1ac308d2372545b37127dedf412d7bcb6 --- src/minicoredumper/corestripper.c | 51 +++++++++++++++++++++++++-------------- 1 file changed, 33 insertions(+), 18 deletions(-) diff --git a/src/minicoredumper/corestripper.c b/src/minicoredumper/corestripper.c index 564c1fa..cb0bc2a 100644 --- a/src/minicoredumper/corestripper.c +++ b/src/minicoredumper/corestripper.c @@ -1494,10 +1494,15 @@ int add_core_data(struct dump_info *di, off64_t dest_offset, size_t len, struct core_data *cur; struct core_data *tmp; int done = 0; - off64_t end; + off64_t end, mem_end; end = start + len; + mem_end = src_offset + len; + /* By default the coredump doesn't contain a file-backed private or shared + * mappings, so it is sometimes impossible to merge two theoretically + * neighboring regions, so below is checking if we can merge regions or if + * we have to insert new block. */ for (cur = di->core_file; cur && !done; cur = cur->next) { if (end < cur->start) { /* insert new block */ @@ -1518,7 +1523,8 @@ int add_core_data(struct dump_info *di, off64_t dest_offset, size_t len, done = 1; } else if (end == cur->start) { - if ((src_offset + len) == cur->mem_start && + if (mem_end == cur->mem_start && + (src_offset + len) == cur->mem_start && src_fd == cur->mem_fd) { /* adjacent block, expand existing block */ cur->start = start; @@ -1545,15 +1551,22 @@ int add_core_data(struct dump_info *di, off64_t dest_offset, size_t len, } else if (start < cur->end) { /* overlapping block, expand existing block */ if (start < cur->start) { - cur->start = start; - cur->mem_start = src_offset; + if (cur->start - start == cur->mem_start - src_offset) { + cur->start = start; + cur->mem_start = src_offset; + done = 1; + } } - if (end > cur->end) - cur->end = end; - done = 1; - + if (end > cur->end) { + if (end - cur->end == mem_end - (cur->mem_start + cur->end - cur->start)) { + cur->end = end; + done = 1; + } + } + if (end <= cur->end) + done = 1; } else if (start == cur->end) { - if (src_offset == (cur->mem_start + len)) { + if (src_offset == (cur->mem_start + (cur->end - cur->start))) { /* adjacent block, expand existing block */ cur->end = end; done = 1; @@ -1562,13 +1575,15 @@ int add_core_data(struct dump_info *di, off64_t dest_offset, size_t len, while (cur->next) { if (cur->next->start < cur->end) { - /* consolidate overlapping block */ - tmp = cur->next; - if (tmp->end > cur->end) - cur->end = tmp->end; - cur->next = tmp->next; - free(tmp); - continue; + if (cur->end - cur->next->start == cur->mem_start + (cur->end - cur->start) - cur->next->mem_start) { + /* consolidate overlapping block */ + tmp = cur->next; + if (tmp->end > cur->end) + cur->end = tmp->end; + cur->next = tmp->next; + free(tmp); + continue; + } } else if (cur->next->start == cur->end) { if (((cur->mem_start + (cur->end - cur->start)) @@ -2003,7 +2018,7 @@ static int dump_vma(struct dump_info *di, unsigned long start, size_t len, dump_end = tmp->mem_end; /* make sure we have something to dump */ - if (dump_start < dump_end) { + if (dump_start < dump_end && dump_start < tmp->file_end) { len = dump_end - dump_start; info("dump: %s: %zu bytes @ 0x%lx", desc ? desc : "", @@ -2703,7 +2718,7 @@ static int dump_data_content_file(struct dump_info *di, char *tmp_path; FILE *file; int len; - int ret; + int ret = 0; len = strlen(di->dst_dir) + strlen("/dumps/") + 32 + strlen(dd->ident) + 1; -- 2.7.4 From m.moscicki2 at partner.samsung.com Tue May 21 14:52:46 2019 From: m.moscicki2 at partner.samsung.com (Mateusz Moscicki) Date: Tue, 21 May 2019 14:52:46 +0200 Subject: [minicoredumper] [PATCH 10/14] minicoredumper: Ignore errors during data copy In-Reply-To: <1558443170-15123-1-git-send-email-m.moscicki2@partner.samsung.com> References: <1558443170-15123-1-git-send-email-m.moscicki2@partner.samsung.com> Message-ID: <1558443170-15123-11-git-send-email-m.moscicki2@partner.samsung.com> Despite checking, copying of some memory regions may fail (e.g. [vvar]). In this case we want to ignore errors and copy a remaining data, to save as much as possible the data in the target core (or fatcore) file. Change-Id: I0b027113fbfd1a9def88174f94eb20916d10eda2 --- src/minicoredumper/corestripper.c | 65 +++++++++++++++++++++++++++------------ 1 file changed, 45 insertions(+), 20 deletions(-) diff --git a/src/minicoredumper/corestripper.c b/src/minicoredumper/corestripper.c index ed2fd97..564c1fa 100644 --- a/src/minicoredumper/corestripper.c +++ b/src/minicoredumper/corestripper.c @@ -922,7 +922,7 @@ static bool is_file(int fd) { * Copy data from a source core to (optionally) multiple destination cores. * Assumes all files are already positioned correctly to begin. */ -static int copy_data(int src, int dest, int dest2, size_t len, char *pagebuf) +static size_t copy_data(int src, int dest, int dest2, size_t len, char *pagebuf) { size_t chunk; int ret; @@ -940,16 +940,16 @@ static int copy_data(int src, int dest, int dest2, size_t len, char *pagebuf) ret = read_file_fd(src, pagebuf, chunk); if (ret < 0) { - info("read core failed at 0x%lx", + info("Couldn't read data at 0x%lx", lseek64(src, 0, SEEK_CUR)); - return -1; + break; } ret = write_func(dest, pagebuf, chunk); if (ret < 0) { info("write core failed at 0x%lx", lseek64(dest, 0, SEEK_CUR)); - return -1; + break; } if (dest2 >= 0) { @@ -957,14 +957,14 @@ static int copy_data(int src, int dest, int dest2, size_t len, char *pagebuf) if (ret < 0) { info("write core2 failed at 0x%lx", lseek64(dest2, 0, SEEK_CUR)); - return -1; + break; } } len -= chunk; } - return 0; + return len; } struct sparse { @@ -1174,6 +1174,41 @@ static void close_compressor(int fd) signal(SIGPIPE, SIG_DFL); } +// In case some memory regions could not be read, minicoredumper will jump +// to the next page instead of return an error code. This situation can +// take place for example on x86 if one of registers points to around +// [vvar] memory region. +static void force_copy_data(int src, int dst, size_t len, char *pagebuf) +{ + while (len > 0) { + off64_t prev_src_offset = lseek64(src, 0, SEEK_CUR); + off64_t prev_dst_offset = lseek64(dst, 0, SEEK_CUR); + + size_t remaining = copy_data(src, dst, -1, len, pagebuf); + + if (remaining != 0) { + off64_t next_page_start = (prev_src_offset + (len - remaining) + (size_t)PAGESZ) & ~(PAGESZ - 1); + off64_t skip = next_page_start - prev_src_offset; + + if (skip > len) + skip = len; + len -= skip; + + info("Skip 0x%" PRIx64 " bytes, read from: 0x%" PRIx64, skip, next_page_start); + if (lseek64(src, prev_src_offset + skip, SEEK_SET) < 0) { + info("lseek64 src to 0x%" PRIx64 " error: %m", prev_src_offset + skip); + break; + } + if (lseek64(dst, prev_dst_offset + skip, SEEK_SET) < 0) { + info("lseek64 dst to 0x%" PRIx64 " error: %m", prev_dst_offset + skip); + break; + } + } else { + len = 0; + } + } +} + static int dump_compressed_tar(struct dump_info *di) { struct core_data *extended_data = NULL; @@ -1325,10 +1360,7 @@ static int dump_compressed_tar(struct dump_info *di) block_bytes_written += cur->start - offset; } - if (copy_data(cur->mem_fd, fd, -1, - cur->end - cur->start, buf) < 0) { - goto out; - } + force_copy_data(cur->mem_fd, fd, cur->end - cur->start, buf); block_bytes_written += cur->end - cur->start; offset = cur->end; } @@ -1393,10 +1425,7 @@ static int dump_compressed_core(struct dump_info *di) dump_zero(fd, cur->start - pos); - if (copy_data(cur->mem_fd, fd, -1, - cur->end - cur->start, buf) < 0) { - goto out; - } + force_copy_data(cur->mem_fd, fd, cur->end - cur->start, buf); pos = cur->end; } @@ -1449,10 +1478,7 @@ static void dump_mini_core(struct dump_info *di) goto out; } - if (copy_data(cur->mem_fd, di->core_fd, -1, - cur->end - cur->start, buf) < 0) { - goto out; - } + force_copy_data(cur->mem_fd, di->core_fd, cur->end - cur->start, buf); } info("core path: %s", di->core_path); @@ -2848,8 +2874,7 @@ static void dump_fat_core(struct dump_info *di) goto out; } - if (copy_data(di->mem_fd, di->fatcore_fd, -1, len, buf) < 0) - break; + copy_data(di->mem_fd, di->fatcore_fd, -1, len, buf); } out: -- 2.7.4 From m.moscicki2 at partner.samsung.com Tue May 21 14:52:48 2019 From: m.moscicki2 at partner.samsung.com (Mateusz Moscicki) Date: Tue, 21 May 2019 14:52:48 +0200 Subject: [minicoredumper] [PATCH 12/14] minicoredumper: Fix writing/reading from file descriptor In-Reply-To: <1558443170-15123-1-git-send-email-m.moscicki2@partner.samsung.com> References: <1558443170-15123-1-git-send-email-m.moscicki2@partner.samsung.com> Message-ID: <1558443170-15123-13-git-send-email-m.moscicki2@partner.samsung.com> Change-Id: I699389dde1963369b5639c9876784f5dfab6bb76 --- src/minicoredumper/corestripper.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/minicoredumper/corestripper.c b/src/minicoredumper/corestripper.c index cb0bc2a..12f8de9 100644 --- a/src/minicoredumper/corestripper.c +++ b/src/minicoredumper/corestripper.c @@ -121,7 +121,8 @@ static ssize_t read_file_fd(int fd, char *dst, int len) if (r > 0) { size += r; len -= r; - } + } else + return size; } while (len > 0); return size; @@ -141,7 +142,8 @@ static ssize_t write_file_fd(int fd, char *src, size_t len) if (r > 0) { size += r; len -= r; - } + } else + return size; } while (len > 0); return size; -- 2.7.4 From m.moscicki2 at partner.samsung.com Tue May 21 14:52:49 2019 From: m.moscicki2 at partner.samsung.com (Mateusz Moscicki) Date: Tue, 21 May 2019 14:52:49 +0200 Subject: [minicoredumper] [PATCH 13/14] minicoredumper: Add an option to dump memory pages pointed by registers In-Reply-To: <1558443170-15123-1-git-send-email-m.moscicki2@partner.samsung.com> References: <1558443170-15123-1-git-send-email-m.moscicki2@partner.samsung.com> Message-ID: <1558443170-15123-14-git-send-email-m.moscicki2@partner.samsung.com> If recept option "dump_pointed_by_regs" is set to true then if a register value looks like a pointer to a memory then store previous, current and next page to the minicoredump. Change-Id: I6f58b7c3549b7ac38e233637be3d6008f281c6f2 --- etc/minicoredumper/generic.recept.json | 3 +- src/minicoredumper/corestripper.c | 39 +++++++++++++++++++++++++ src/minicoredumper/minicoredumper.recept.json.5 | 3 ++ src/minicoredumper/prog_config.c | 3 ++ src/minicoredumper/prog_config.h | 1 + 5 files changed, 48 insertions(+), 1 deletion(-) diff --git a/etc/minicoredumper/generic.recept.json b/etc/minicoredumper/generic.recept.json index 15406fb..fe24195 100644 --- a/etc/minicoredumper/generic.recept.json +++ b/etc/minicoredumper/generic.recept.json @@ -22,5 +22,6 @@ "live_dumper": true, "write_proc_info": false, "write_debug_log": false, - "dump_fat_core": false + "dump_fat_core": false, + "dump_pointed_by_regs": true } diff --git a/src/minicoredumper/corestripper.c b/src/minicoredumper/corestripper.c index 12f8de9..c0d6514 100644 --- a/src/minicoredumper/corestripper.c +++ b/src/minicoredumper/corestripper.c @@ -31,6 +31,7 @@ #include #include #include +#include #include "prog_config.h" #include "dump_data_private.h" @@ -3542,6 +3543,41 @@ static int add_dumplist_section(struct dump_info *di) } #endif +void dump_pointed_by_registers_for_tasknr(struct dump_info *di, int tsk_nr) +{ + char *msg; + struct elf_greg_t *regs = (struct elf_greg_t *)&di->tsks[tsk_nr].pr_reg; + elf_greg_t region, registers[ELF_NGREG]; + + memcpy(registers, regs, sizeof(registers)); + + for (int i = 0; i < ELF_NGREG; i++) { + if (get_vma_pos(di, registers[i]) != NULL) { + region = (registers[i] & (~(PAGESZ-1))) - PAGESZ; + int ret; +#if defined(__x86_64__) + ret = asprintf(&msg, "pointed by register 0x%llx (0x%llx - 0x%llx)", registers[i], region, region + 3*PAGESZ); +#else + ret = asprintf(&msg, "pointed by register 0x%lx (0x%lx - 0x%lx)", registers[i], region, region + 3*PAGESZ); +#endif + if (ret == -1) { + info("unable to allocate memory: %m"); + continue; + } + dump_vma(di, region, PAGESZ, 0, msg); + dump_vma(di, region + PAGESZ, PAGESZ, 0, msg); + dump_vma(di, region + 2*PAGESZ, PAGESZ, 0, msg); + free(msg); + } + } +} + +void dump_pointed_by_registers(struct dump_info *di) +{ + for (int i = 0; i < di->ntsks; i++) + dump_pointed_by_registers_for_tasknr(di, i); +} + static void do_dump(struct dump_info *di) { int ret; @@ -3600,6 +3636,9 @@ static void do_dump(struct dump_info *di) get_interesting_buffers(di); } + if (di->cfg->prog_config.dump_pointed_by_regs) + dump_pointed_by_registers(di); + /* dump registered application data */ dyn_dump(di); diff --git a/src/minicoredumper/minicoredumper.recept.json.5 b/src/minicoredumper/minicoredumper.recept.json.5 index 4bac92b..0d66b20 100644 --- a/src/minicoredumper/minicoredumper.recept.json.5 +++ b/src/minicoredumper/minicoredumper.recept.json.5 @@ -88,6 +88,9 @@ particularly useful if .BR syslog (3) is not available on the system. .TP +.B dump_pointed_by_regs +(boolean) Dump pages that are pointed by register values. Minicoredumper will also save one page before and one after. +.TP .B dump_fat_core (boolean) Whether all virtual memory areas should be dumped. This will generate a separate "fatcore" file that is typically larger diff --git a/src/minicoredumper/prog_config.c b/src/minicoredumper/prog_config.c index a9b8b09..a58da3e 100644 --- a/src/minicoredumper/prog_config.c +++ b/src/minicoredumper/prog_config.c @@ -408,6 +408,9 @@ static int read_prog_config(struct json_object *root, struct prog_config *cfg) if (get_json_boolean(v, &cfg->live_dumper) != 0) return -1; + } else if (strcmp(n, "dump_pointed_by_regs") == 0) { + if (get_json_boolean(v, &cfg->dump_pointed_by_regs) != 0) + return -1; } else { info("WARNING: ignoring unknown config item: %s", n); } diff --git a/src/minicoredumper/prog_config.h b/src/minicoredumper/prog_config.h index 5d77f2d..9d69153 100644 --- a/src/minicoredumper/prog_config.h +++ b/src/minicoredumper/prog_config.h @@ -54,6 +54,7 @@ struct prog_config { bool write_debug_log; bool live_dumper; unsigned int dump_scope; + bool dump_pointed_by_regs; }; struct config { -- 2.7.4 From m.moscicki2 at partner.samsung.com Tue May 21 14:52:50 2019 From: m.moscicki2 at partner.samsung.com (Mateusz Moscicki) Date: Tue, 21 May 2019 14:52:50 +0200 Subject: [minicoredumper] [PATCH 14/14] minicoredumper: Add option to exclude specified files from copying from proc In-Reply-To: <1558443170-15123-1-git-send-email-m.moscicki2@partner.samsung.com> References: <1558443170-15123-1-git-send-email-m.moscicki2@partner.samsung.com> Message-ID: <1558443170-15123-15-git-send-email-m.moscicki2@partner.samsung.com> To exclude some files, add option to recipe file, e.g.: "proc_info_exclude": [ "smaps", "maps" ] Possible names for exclusion: * cmdline * environ * io * maps * smaps * stack * stat * statm * cwd * fd Change-Id: I476e3448e1f0f8469b5a39ce5f32917f7126e4ce --- etc/minicoredumper/generic.recept.json | 5 ++- src/minicoredumper/corestripper.c | 12 +++++++ src/minicoredumper/minicoredumper.recept.json.5 | 13 +++++++ src/minicoredumper/prog_config.c | 47 +++++++++++++++++++++++++ src/minicoredumper/prog_config.h | 6 ++++ 5 files changed, 82 insertions(+), 1 deletion(-) diff --git a/etc/minicoredumper/generic.recept.json b/etc/minicoredumper/generic.recept.json index fe24195..70108be 100644 --- a/etc/minicoredumper/generic.recept.json +++ b/etc/minicoredumper/generic.recept.json @@ -20,7 +20,10 @@ "dump_scope": 1024, "dump_build_id": false, "live_dumper": true, - "write_proc_info": false, + "write_proc_info": true, + "proc_info_exclude": [ + "smaps" + ], "write_debug_log": false, "dump_fat_core": false, "dump_pointed_by_regs": true diff --git a/src/minicoredumper/corestripper.c b/src/minicoredumper/corestripper.c index c0d6514..b877a09 100644 --- a/src/minicoredumper/corestripper.c +++ b/src/minicoredumper/corestripper.c @@ -2946,6 +2946,15 @@ static int copy_link(const char *dest, const char *src) return ret; } +static bool is_file_name_excluded(const char *name, struct dump_info *di) +{ + for (int i = 0; i < di->cfg->prog_config.proc_excludes.count; i++) { + if (strncmp(name, di->cfg->prog_config.proc_excludes.filenames[i], strlen(name)) == 0) + return true; + } + return false; +} + static void copy_proc_files(struct dump_info *di, int tasks, const char *name, int link) { @@ -2957,6 +2966,9 @@ static void copy_proc_files(struct dump_info *di, int tasks, const char *name, DIR *d; int i; + if (is_file_name_excluded(name, di)) + return; + base_len = strlen(di->dst_dir); /* assume maximum length expected */ diff --git a/src/minicoredumper/minicoredumper.recept.json.5 b/src/minicoredumper/minicoredumper.recept.json.5 index 0d66b20..043eea7 100644 --- a/src/minicoredumper/minicoredumper.recept.json.5 +++ b/src/minicoredumper/minicoredumper.recept.json.5 @@ -80,6 +80,19 @@ applications when a dump occurs. (boolean) Whether interesting /proc files should be copied to the dump directory. .TP +.B proc_info_exclude +(array of strings) Allows to specify which files shouldn't be copied. Allowed values: +.I cmdline +.I environ +.I io +.I maps +.I smaps +.I stack +.I stat +.I statm +.I cwd +.I fd +.TP .B write_debug_log (boolean) Whether .BR minicoredumper (1) diff --git a/src/minicoredumper/prog_config.c b/src/minicoredumper/prog_config.c index a58da3e..e225cef 100644 --- a/src/minicoredumper/prog_config.c +++ b/src/minicoredumper/prog_config.c @@ -331,6 +331,43 @@ static int read_prog_stack_config(struct json_object *root, return 0; } +static int read_proc_info_exclude_config(struct json_object *root, + struct proc_info_exclude_config *cfg) +{ + int len; + int i; + int res = 0; + if (!json_object_is_type(root, json_type_array)) + return -1; + + len = json_object_array_length(root); + if (len < 1) + return 0; + + cfg->filenames = calloc(len, sizeof(char *)); + if (!cfg->filenames) + return -1; + + for (i = 0; i < len; i++) { + struct json_object *v; + + v = json_object_array_get_idx(root, i); + if (!v) { + res = -1; + break; + } + + cfg->filenames[i] = alloc_json_string(v); + if (!cfg->filenames[i]) { + res = -1; + break; + } + } + cfg->count = i; + + return res; +} + static int read_prog_config(struct json_object *root, struct prog_config *cfg) { struct json_object_iterator it_end; @@ -411,6 +448,9 @@ static int read_prog_config(struct json_object *root, struct prog_config *cfg) } else if (strcmp(n, "dump_pointed_by_regs") == 0) { if (get_json_boolean(v, &cfg->dump_pointed_by_regs) != 0) return -1; + } else if (strcmp(n, "proc_info_exclude") == 0) { + if (read_proc_info_exclude_config(v, &cfg->proc_excludes) != 0) + return -1; } else { info("WARNING: ignoring unknown config item: %s", n); } @@ -708,6 +748,11 @@ static void set_config_defaults(struct prog_config *cfg) /* dump NT_GNU_BUILD_ID */ cfg->dump_build_id = false; + + /* Array of excluded files */ + cfg->proc_excludes.count = 0; + cfg->proc_excludes.filenames = NULL; + } int init_prog_config(struct config *cfg, const char *cfg_file) @@ -756,6 +801,8 @@ void free_config(struct config *cfg) for (i = 0; i < cfg->prog_config.maps.nglobs; i++) free(cfg->prog_config.maps.name_globs[i]); + for (i = 0; i < cfg->prog_config.proc_excludes.count; i++) + free(cfg->prog_config.proc_excludes.filenames[i]); if (cfg->prog_config.maps.name_globs) free(cfg->prog_config.maps.name_globs); diff --git a/src/minicoredumper/prog_config.h b/src/minicoredumper/prog_config.h index 9d69153..2f57c12 100644 --- a/src/minicoredumper/prog_config.h +++ b/src/minicoredumper/prog_config.h @@ -37,10 +37,16 @@ struct maps_config { size_t nglobs; }; +struct proc_info_exclude_config { + char **filenames; + size_t count; +}; + struct prog_config { struct stack_config stack; struct maps_config maps; struct interesting_buffer *buffers; + struct proc_info_exclude_config proc_excludes; char *core_compressor; char *core_compressor_ext; bool core_in_tar; -- 2.7.4 From john.ogness at linutronix.de Tue May 21 18:54:39 2019 From: john.ogness at linutronix.de (John Ogness) Date: Tue, 21 May 2019 18:54:39 +0200 Subject: [minicoredumper] [PATCH 00/14] Set of different changes In-Reply-To: <1558443170-15123-1-git-send-email-m.moscicki2@partner.samsung.com> (Mateusz Moscicki's message of "Tue, 21 May 2019 14:52:36 +0200") References: <1558443170-15123-1-git-send-email-m.moscicki2@partner.samsung.com> Message-ID: <87o93v929c.fsf@linutronix.de> On 2019-05-21, Mateusz Moscicki wrote: > I realize that these changes don't have to be consistent with the > author's vision, but we just wanted to share our work, because some of > them may be useful. Thank you for sharing this! I will respond to the patches individually with comments and/or confirmation if they are committed to git. John Ogness