コード例 #1
0
static void
print_address (Dwfl_Module *mod, Dwarf_Addr address)
{
  int n = dwfl_module_relocations (mod);
  if (n < 0)
    error (0, 0, "dwfl_module_relocations: %s", dwfl_errmsg (-1));
  else if (n > 0)
    {
      int i = dwfl_module_relocate_address (mod, &address);
      if (i < 0)
	error (0, 0, "dwfl_module_relocate_address: %s", dwfl_errmsg (-1));
      else
	{
	  const char *modname = dwfl_module_info (mod, NULL, NULL, NULL,
						  NULL, NULL, NULL, NULL);
	  const char *secname = dwfl_module_relocation_info (mod, i, NULL);
	  if (n > 1 || secname[0] != '\0')
	    printf ("%s(%s)+%#" PRIx64, modname, secname, address);
	  else
	    printf ("%s+%#" PRIx64, modname, address);
	  return;
	}
    }

  printf ("%#" PRIx64, address);
}
コード例 #2
0
ファイル: Libdw.c プロジェクト: momiken/ghc
// Create a libdw session with DWARF information for all loaded modules
LibdwSession *libdwInit() {
    LibdwSession *session = stgCallocBytes(1, sizeof(LibdwSession),
                                           "libdwInit");
    // Initialize ELF library
    if (elf_version(EV_CURRENT) == EV_NONE) {
        sysErrorBelch("libelf version too old!");
        return NULL;
    }

    // Initialize a libdwfl session
    static char *debuginfo_path;
    static const Dwfl_Callbacks proc_callbacks =
        {
            .find_debuginfo = dwfl_standard_find_debuginfo,
            .debuginfo_path = &debuginfo_path,
            .find_elf = dwfl_linux_proc_find_elf,
        };
    session->dwfl = dwfl_begin (&proc_callbacks);
    if (session->dwfl == NULL) {
        sysErrorBelch("dwfl_begin failed: %s", dwfl_errmsg(dwfl_errno()));
        free(session);
        return NULL;
    }

    // Report the loaded modules
    int ret = dwfl_linux_proc_report(session->dwfl, getpid());
    if (ret < 0) {
        sysErrorBelch("dwfl_linux_proc_report failed: %s",
                      dwfl_errmsg(dwfl_errno()));
        goto fail;
    }
    if (dwfl_report_end (session->dwfl, NULL, NULL) != 0) {
        sysErrorBelch("dwfl_report_end failed: %s", dwfl_errmsg(dwfl_errno()));
        goto fail;
    }

    pid_t pid = getpid();
    if (! dwfl_attach_state(session->dwfl, NULL, pid, &thread_cbs, NULL)) {
        sysErrorBelch("dwfl_attach_state failed: %s",
                      dwfl_errmsg(dwfl_errno()));
        goto fail;
    }

    return session;

 fail:
    dwfl_end(session->dwfl);
    free(session);
    return NULL;
}
コード例 #3
0
ファイル: backtrace-dwarf.c プロジェクト: Distrotech/elfutils
static int
frame_callback (Dwfl_Frame *state, void *frame_arg)
{
  Dwarf_Addr pc;
  bool isactivation;
  if (! dwfl_frame_pc (state, &pc, &isactivation))
    {
      error (0, 0, "%s", dwfl_errmsg (-1));
      return DWARF_CB_ABORT;
    }
  Dwarf_Addr pc_adjusted = pc - (isactivation ? 0 : 1);

  /* Get PC->SYMNAME.  */
  Dwfl_Thread *thread = dwfl_frame_thread (state);
  Dwfl *dwfl = dwfl_thread_dwfl (thread);
  Dwfl_Module *mod = dwfl_addrmodule (dwfl, pc_adjusted);
  const char *symname = NULL;
  if (mod)
    symname = dwfl_module_addrname (mod, pc_adjusted);

  printf ("%#" PRIx64 "\t%s\n", (uint64_t) pc, symname);

  if (symname && (strcmp (symname, "main") == 0
		  || strcmp (symname, ".main") == 0))
    {
      kill (dwfl_pid (dwfl), SIGKILL);
      exit (0);
    }

  return DWARF_CB_OK;
}
コード例 #4
0
ファイル: core_unwind.c プロジェクト: credmon/satyr
static int
touch_module(Dwfl_Module *mod, void **userdata, const char *name,
             Dwarf_Addr start_addr, void *arg)
{
    struct exe_mapping_data ***tailp = arg;
    const char *filename = NULL;
    GElf_Addr bias;
    Dwarf_Addr base;

    if (dwfl_module_getelf (mod, &bias) == NULL)
    {
        warn("cannot find ELF for '%s': %s", name, dwfl_errmsg(-1));
        return DWARF_CB_OK;
    }

    dwfl_module_info(mod, NULL, &base, NULL, NULL, NULL, &filename, NULL);

    if (filename)
    {
        **tailp = sr_mallocz(sizeof(struct exe_mapping_data));
        (**tailp)->start = (uint64_t)base;
        (**tailp)->filename = sr_strdup(filename);
        *tailp = &((**tailp)->next);
    }

    return DWARF_CB_OK;
}
コード例 #5
0
ファイル: backtrace-dwarf.c プロジェクト: Distrotech/elfutils
static int
thread_callback (Dwfl_Thread *thread, void *thread_arg)
{
  dwfl_thread_getframes (thread, frame_callback, NULL);
  /* frame_callback shall exit (0) on success.  */
  error (1, 0, "dwfl_thread_getframes: %s", dwfl_errmsg (-1));
  return DWARF_CB_ABORT;
}
コード例 #6
0
ファイル: backtrace-dwarf.c プロジェクト: Distrotech/elfutils
static void
report_pid (Dwfl *dwfl, pid_t pid)
{
  int result = dwfl_linux_proc_report (dwfl, pid);
  if (result < 0)
    error (2, 0, "dwfl_linux_proc_report: %s", dwfl_errmsg (-1));
  else if (result > 0)
    error (2, result, "dwfl_linux_proc_report");

  if (dwfl_report_end (dwfl, NULL, NULL) != 0)
    error (2, 0, "dwfl_report_end: %s", dwfl_errmsg (-1));

  result = dwfl_linux_proc_attach (dwfl, pid, true);
  if (result < 0)
    error (2, 0, "dwfl_linux_proc_attach: %s", dwfl_errmsg (-1));
  else if (result > 0)
    error (2, result, "dwfl_linux_proc_attach");
}
コード例 #7
0
ファイル: skip-callchain-idx.c プロジェクト: 020gzh/linux
/*
 * Get the DWARF frame from the .eh_frame section.
 */
static Dwarf_Frame *get_eh_frame(Dwfl_Module *mod, Dwarf_Addr pc)
{
	int		result;
	Dwarf_Addr	bias;
	Dwarf_CFI	*cfi;
	Dwarf_Frame	*frame;

	cfi = dwfl_module_eh_cfi(mod, &bias);
	if (!cfi) {
		pr_debug("%s(): no CFI - %s\n", __func__, dwfl_errmsg(-1));
		return NULL;
	}

	result = dwarf_cfi_addrframe(cfi, pc-bias, &frame);
	if (result) {
		pr_debug("%s(): %s\n", __func__, dwfl_errmsg(-1));
		return NULL;
	}

	return frame;
}
コード例 #8
0
/* This callback is invoked for every frame in a thread. From a Dwfl_Frame, we
 * are able to extract the program counter (PC), and from that, the procedure
 * name via a Dwfl_Module.
 */
static int frame_cb(Dwfl_Frame *frame, void *userdata)
{
        Dwarf_Addr pc;
        Dwarf_Addr pc_adjusted;
        Dwfl_Module *module;
        const char *procname;
        const char *modname;
        bool activation;
        GString **bt = (GString **)userdata;

        if (!dwfl_frame_pc(frame, &pc, &activation)) {
                errorstr = g_strdup_printf("Failed to find program counter for"
                                           " current frame: %s\n",
                                           dwfl_errmsg(-1));
                return DWARF_CB_ABORT;
        }

        // The return address may be beyond the calling address, putting the
        // current PC in a different context. Subtracting 1 from PC in this
        // case generally puts it back in the same context, thus fixing the
        // virtual unwind for this frame. See the DWARF standard for details.
        if (!activation) {
                pc_adjusted = pc - 1;
        } else {
                pc_adjusted = pc;
        }

        module = dwfl_addrmodule(d_core, pc_adjusted);

        if (!module) {
                errorstr = g_strdup("Failed to find module for current"
                                    " frame\n");
                return DWARF_CB_ABORT;
        }

        modname = dwfl_module_info(module, NULL, NULL, NULL, NULL, NULL, NULL,
                                   NULL);
        procname = dwfl_module_addrname(module, pc_adjusted);

        if (procname && modname) {
                g_string_append_printf(*bt, "#%u %s() - [%s]\n",
                                       frame_counter++, procname, modname);
        } else if (modname) {
                g_string_append_printf(*bt, "#%u ??? - [%s]\n",
                                       frame_counter++, modname);
        } else {
                // TODO: decide on "no symbol" representation
                g_string_append_printf(*bt, "#%u (no symbols)\n",
                                       frame_counter++);
        }

        return DWARF_CB_OK;
}
コード例 #9
0
ファイル: core_unwind_elfutils.c プロジェクト: lkundrak/satyr
static int
unwind_thread(Dwfl_Thread *thread, void *data)
{
    struct thread_callback_arg *thread_arg = data;
    char **error_msg = &thread_arg->error_msg;

    struct sr_core_thread *result = sr_core_thread_new();
    if (!result)
    {
        set_error("Failed to initialize stacktrace memory");
        return DWARF_CB_ABORT;
    }
    result->id = (int64_t)dwfl_thread_tid(thread);

    struct frame_callback_arg frame_arg =
    {
        .thread = result,
        .error_msg = NULL
    };

    int ret = dwfl_thread_getframes(thread, frame_callback, &frame_arg);
    if (ret == -1)
    {
        warn("dwfl_thread_getframes failed for thread id %d: %s",
             (int)result->id, dwfl_errmsg(-1));
    }
    else if (ret == DWARF_CB_ABORT)
    {
        *error_msg = frame_arg.error_msg;
        goto abort;
    }
    else if (ret != 0 && ret != CB_STOP_UNWIND)
    {
        *error_msg = sr_strdup("Unknown error in dwfl_thread_getframes");
        goto abort;
    }

    if (!error_msg && !frame_arg.thread->frames)
    {
        set_error("No frames found for thread id %d", (int)result->id);
        goto abort;
    }

    thread_arg->stacktrace->threads =
        sr_core_thread_append(thread_arg->stacktrace->threads, result);
    return DWARF_CB_OK;

abort:
    sr_core_thread_free(result);
    return DWARF_CB_ABORT;
}
コード例 #10
0
ファイル: dwarf.c プロジェクト: j3rgus/pb173-bin
int main(void)
{
	Dwfl *dw;
	Dwfl_Module *mod;
	Dwarf_Addr bias;
	Dwarf_Die *die = NULL;

	dw = dwfl_begin(&cb);
	if (!dw)
		errx(1, "dwfl_begin %s", dwfl_errmsg(-1));

	mod = dwfl_report_offline(dw, "", "tst", -1);
	if (!mod)
		errx(1, "dwfl_begin %s", dwfl_errmsg(-1));

	while ((die = dwfl_nextcu(dw, die, &bias))) {
		print_die_rec(die, -1);
		printf("\n");
	}

	dwfl_end(dw);
	return 0;
}
コード例 #11
0
ファイル: backtrace-dwarf.c プロジェクト: Distrotech/elfutils
static Dwfl *
pid_to_dwfl (pid_t pid)
{
  static char *debuginfo_path;
  static const Dwfl_Callbacks proc_callbacks =
    {
      .find_debuginfo = dwfl_standard_find_debuginfo,
      .debuginfo_path = &debuginfo_path,

      .find_elf = dwfl_linux_proc_find_elf,
    };
  Dwfl *dwfl = dwfl_begin (&proc_callbacks);
  if (dwfl == NULL)
    error (2, 0, "dwfl_begin: %s", dwfl_errmsg (-1));
  report_pid (dwfl, pid);
  return dwfl;
}
コード例 #12
0
static int
handle_cfi (Dwfl *dwfl, const char *which, Dwarf_CFI *cfi,
	    GElf_Addr pc, struct stuff *stuff)
{
  int result = dwarf_cfi_addrframe (cfi, pc - stuff->bias, &stuff->frame);
  if (result != 0)
    {
      error (0, 0, "dwarf_addrframe (%s): %s", which, dwfl_errmsg (-1));
      return 1;
    }

  Dwarf_Addr start = pc;
  Dwarf_Addr end = pc;
  bool signalp;
  int ra_regno = dwarf_frame_info (stuff->frame, &start, &end, &signalp);
  if (ra_regno >= 0)
    {
      start += stuff->bias;
      end += stuff->bias;
    }

  printf ("%s has %#" PRIx64 " => [%#" PRIx64 ", %#" PRIx64 "):\n",
	  which, pc, start, end);

  if (ra_regno < 0)
    printf ("\treturn address register unavailable (%s)\n",
	    dwarf_errmsg (0));
  else
    printf ("\treturn address in reg%u%s\n",
	    ra_regno, signalp ? " (signal frame)" : "");

  Dwarf_Op *cfa_ops;
  size_t cfa_nops;
  result = dwarf_frame_cfa (stuff->frame, &cfa_ops, &cfa_nops);

  printf ("\tCFA ");
  print_detail (result, cfa_ops, cfa_nops, stuff->bias);

  (void) dwfl_module_register_names (dwfl_addrmodule (dwfl, pc),
				     &print_register, stuff);

  return 0;
}
コード例 #13
0
ファイル: Libdw.c プロジェクト: momiken/ghc
Backtrace *libdwGetBacktrace(LibdwSession *session) {
    if (session->cur_bt != NULL) {
        sysErrorBelch("Already collecting backtrace. Uh oh.");
        return NULL;
    }

    Backtrace *bt = backtraceAlloc();
    session->cur_bt = bt;

    int pid = getpid();
    int ret = dwfl_getthread_frames(session->dwfl, pid,
                                    getBacktraceFrameCb, session);
    if (ret == -1)
        sysErrorBelch("Failed to get stack frames of current process: %s",
                      dwfl_errmsg(dwfl_errno()));

    session->cur_bt = NULL;
    return bt;
}
コード例 #14
0
ファイル: backtrace-dwarf.c プロジェクト: Distrotech/elfutils
int
main (int argc __attribute__ ((unused)), char **argv)
{
  /* We use no threads here which can interfere with handling a stream.  */
  __fsetlocking (stdin, FSETLOCKING_BYCALLER);
  __fsetlocking (stdout, FSETLOCKING_BYCALLER);
  __fsetlocking (stderr, FSETLOCKING_BYCALLER);

  /* Set locale.  */
  (void) setlocale (LC_ALL, "");

  elf_version (EV_CURRENT);

  pid_t pid = fork ();
  switch (pid)
  {
    case -1:
      abort ();
    case 0:;
      long l = ptrace (PTRACE_TRACEME, 0, NULL, NULL);
      assert (errno == 0);
      assert (l == 0);
      cleanup_13_main ();
      abort ();
    default:
      break;
  }

  errno = 0;
  int status;
  pid_t got = waitpid (pid, &status, 0);
  assert (errno == 0);
  assert (got == pid);
  assert (WIFSTOPPED (status));
  assert (WSTOPSIG (status) == SIGABRT);

  Dwfl *dwfl = pid_to_dwfl (pid);
  dwfl_getthreads (dwfl, thread_callback, NULL);

  /* There is an exit (0) call if we find the "main" frame,  */
  error (1, 0, "dwfl_getthreads: %s", dwfl_errmsg (-1));
}
コード例 #15
0
static int thread_cb(Dwfl_Thread *thread, void *userdata)
{
        int ret;
        GString **bt = (GString **)userdata;
        pid_t tid;

        tid = dwfl_thread_tid(thread);

        g_string_append_printf(*bt, "\nBacktrace (TID %u):\n",
                               (unsigned int)tid);

        ret = dwfl_thread_getframes(thread, frame_cb, userdata);

        switch (ret) {
                case -1:
                        errorstr = g_strdup_printf("Error while iterating"
                                                   " through frames for thread"
                                                   " %u: %s\n",
                                                   (unsigned int)tid,
                                                   dwfl_errmsg(-1));
                        return DWARF_CB_ABORT;
                case DWARF_CB_ABORT:
                        /* already set the error string in frame_cb */
                        return DWARF_CB_ABORT;
                case DWARF_CB_OK:
                        break;
                default:
                        telem_log(LOG_ERR, "Unrecognized return code\n");
                        return DWARF_CB_ABORT;
        }

        // New threads (if any), will require a fresh frame counter
        frame_counter = 0;

#if 0
        g_string_append_printf(*bt, "\nRegisters (TID %u):\nTODO\n", current,
                               (unsigned int)tid);
#endif

        return DWARF_CB_OK;
}
コード例 #16
0
static int
handle_function (Dwarf_Die *funcdie, void *arg)
{
  struct args *a = arg;

  const char *name = dwarf_diename (funcdie);
  char **argv = a->argv;
  if (argv[0] != NULL)
    {
      bool match;
      do
	match = fnmatch (*argv, name, 0) == 0;
      while (!match && *++argv);
      if (!match)
	return 0;
    }

  printf ("(%s) %s: ", dwfl_module_info (dwfl_cumodule (a->cu), NULL,
					 NULL, NULL,
					 NULL, NULL,
					 NULL, NULL), name);

  const Dwarf_Op *locops;
  int nlocops = dwfl_module_return_value_location (dwfl_cumodule (a->cu),
						   funcdie, &locops);
  if (nlocops < 0)
    error (EXIT_FAILURE, 0, "dwfl_module_return_value_location: %s",
	   dwfl_errmsg (-1));
  else if (nlocops == 0)
    puts ("returns no value");
  else
    {
      printf ("return value location:");
      for (int i = 0; i < nlocops; ++i)
	printf (" {%#x, %#" PRIx64 "}", locops[i].atom, locops[i].number);
      puts ("");
    }

  return 0;
}
コード例 #17
0
ファイル: crash_probe.c プロジェクト: balagopalraj/clearlinux
static inline void tm_dwfl_err(const char *msg)
{
        telem_log(LOG_ERR, "%s: %s\n", msg, dwfl_errmsg(-1));
}
コード例 #18
0
void
output_right(enum tof type, struct process *proc, struct library_symbol *libsym,
             struct timedelta *spent)
{
    assert(! options.summary);

    struct prototype *func = lookup_symbol_prototype(proc, libsym);
    if (func == NULL)
        return;

    if (current_proc != NULL
            && (current_proc != proc
                || current_depth != proc->callstack_depth)) {
        fprintf(options.output, " <unfinished ...>\n");
        current_proc = NULL;
    }
    if (current_proc != proc) {
        begin_of_line(proc, type == LT_TOF_FUNCTIONR, 1);
#ifdef USE_DEMANGLE
        current_column +=
            fprintf(options.output, "<... %s resumed> ",
                    options.demangle ? my_demangle(libsym->name)
                    : libsym->name);
#else
        current_column +=
            fprintf(options.output, "<... %s resumed> ", libsym->name);
#endif
    }

    struct callstack_element *stel
            = &proc->callstack[proc->callstack_depth - 1];

    struct fetch_context *context = stel->fetch_context;

    /* Fetch & enter into dictionary the retval first, so that
     * other values can use it in expressions.  */
    struct value retval;
    bool own_retval = false;
    if (context != NULL) {
        value_init(&retval, proc, NULL, func->return_info, 0);
        own_retval = true;
        if (fetch_retval(context, type, proc, func->return_info,
                         &retval) < 0)
            value_set_type(&retval, NULL, 0);
        else if (stel->arguments != NULL
                 && val_dict_push_named(stel->arguments, &retval,
                                        "retval", 0) == 0)
            own_retval = false;
    }

    if (stel->arguments != NULL)
        output_params(stel->arguments, stel->out.params_left,
                      val_dict_count(stel->arguments),
                      &stel->out.need_delim);

    current_column += fprintf(options.output, ") ");
    tabto(options.align - 1);
    fprintf(options.output, "= ");

    if (context != NULL && retval.type != NULL) {
        struct format_argument_data data = { &retval, stel->arguments };
        format_argument_cb(options.output, &data);
    }

    if (own_retval)
        value_destroy(&retval);

    if (opt_T) {
        assert(spent != NULL);
        fprintf(options.output, " <%lu.%06d>",
                (unsigned long) spent->tm.tv_sec,
                (int) spent->tm.tv_usec);
    }

    fprintf(options.output, "\n");

#if defined(HAVE_LIBUNWIND)
    if (options.bt_depth > 0
            && proc->unwind_priv != NULL
            && proc->unwind_as != NULL) {
        unw_cursor_t cursor;
        arch_addr_t ip, function_offset;
        struct library *lib = NULL;
        int unwind_depth = options.bt_depth;
        char fn_name[100];
        const char *lib_name;
        size_t distance;

        /* Verify that we can safely cast arch_addr_t* to
         * unw_word_t*.  */
        (void)sizeof(char[1 - 2*(sizeof(unw_word_t)
                                 != sizeof(arch_addr_t))]);
        unw_init_remote(&cursor, proc->unwind_as, proc->unwind_priv);
        while (unwind_depth) {

            int rc = unw_get_reg(&cursor, UNW_REG_IP,
                                 (unw_word_t *) &ip);
            if (rc < 0) {
                fprintf(options.output, " > Error: %s\n",
                        unw_strerror(rc));
                goto cont;
            }

            /* We are looking for the library with the base address
             * closest to the current ip.  */
            lib_name = "unmapped_area";
            distance = (size_t) -1;
            lib = proc->libraries;
            while (lib != NULL) {
                /* N.B.: Assumes sizeof(size_t) ==
                 * sizeof(arch_addr_t).
                 * Keyword: double cast.  */
                if ((ip >= lib->base) &&
                        ((size_t)(ip - lib->base)
                         < distance)) {
                    distance = ip - lib->base;
                    lib_name = lib->pathname;
                }
                lib = lib->next;
            }

            rc = unw_get_proc_name(&cursor, fn_name,
                                   sizeof(fn_name),
                                   (unw_word_t *) &function_offset);
            if (rc == 0 || rc == -UNW_ENOMEM)
                fprintf(options.output, " > %s(%s+%p) [%p]\n",
                        lib_name, fn_name, function_offset, ip);
            else
                fprintf(options.output, " > %s(??\?) [%p]\n",
                        lib_name, ip);

cont:
            if (unw_step(&cursor) <= 0)
                break;
            unwind_depth--;
        }
        fprintf(options.output, "\n");
    }
#endif /* defined(HAVE_LIBUNWIND) */

#if defined(HAVE_LIBDW)
    if (options.bt_depth > 0 && proc->leader->dwfl != NULL) {
        int frames = options.bt_depth;
        if (dwfl_getthread_frames(proc->leader->dwfl, proc->pid,
                                  frame_callback, &frames) < 0) {
            // Only print an error if we couldn't show anything.
            // Otherwise just show there might be more...
            if (frames == options.bt_depth)
                fprintf(stderr,
                        "dwfl_getthread_frames tid %d: %s\n",
                        proc->pid, dwfl_errmsg(-1));
            else
                fprintf(options.output, " > [...]\n");
        }
        fprintf(options.output, "\n");
    }
#endif /* defined(HAVE_LIBDW) */

    current_proc = NULL;
    current_column = 0;
}
コード例 #19
0
ファイル: coredump.c プロジェクト: rothwerx/systemd
int main(int argc, char* argv[]) {

        /* The small core field we allocate on the stack, to keep things simple */
        char
                *core_pid = NULL, *core_uid = NULL, *core_gid = NULL, *core_signal = NULL,
                *core_session = NULL, *core_exe = NULL, *core_comm = NULL, *core_cmdline = NULL,
                *core_cgroup = NULL, *core_cwd = NULL, *core_root = NULL, *core_unit = NULL,
                *core_slice = NULL;

        /* The larger ones we allocate on the heap */
        _cleanup_free_ char
                *core_timestamp = NULL,  *core_message = NULL, *coredump_data = NULL, *core_owner_uid = NULL,
                *core_open_fds = NULL, *core_proc_status = NULL, *core_proc_maps = NULL, *core_proc_limits = NULL,
                *core_proc_cgroup = NULL, *core_environ = NULL;

        _cleanup_free_ char *exe = NULL, *comm = NULL, *filename = NULL;
        const char *info[_INFO_LEN];

        _cleanup_close_ int coredump_fd = -1;

        struct iovec iovec[26];
        uint64_t coredump_size;
        int r, j = 0;
        uid_t uid, owner_uid;
        gid_t gid;
        pid_t pid;
        char *t;
        const char *p;

        /* Make sure we never enter a loop */
        prctl(PR_SET_DUMPABLE, 0);

        /* First, log to a safe place, since we don't know what
         * crashed and it might be journald which we'd rather not log
         * to then. */
        log_set_target(LOG_TARGET_KMSG);
        log_open();

        if (argc < INFO_COMM + 1) {
                log_error("Not enough arguments passed from kernel (%d, expected %d).",
                          argc - 1, INFO_COMM + 1 - 1);
                r = -EINVAL;
                goto finish;
        }

        /* Ignore all parse errors */
        parse_config();

        log_debug("Selected storage '%s'.", coredump_storage_to_string(arg_storage));
        log_debug("Selected compression %s.", yes_no(arg_compress));

        r = parse_uid(argv[INFO_UID + 1], &uid);
        if (r < 0) {
                log_error("Failed to parse UID.");
                goto finish;
        }

        r = parse_pid(argv[INFO_PID + 1], &pid);
        if (r < 0) {
                log_error("Failed to parse PID.");
                goto finish;
        }

        r = parse_gid(argv[INFO_GID + 1], &gid);
        if (r < 0) {
                log_error("Failed to parse GID.");
                goto finish;
        }

        if (get_process_comm(pid, &comm) < 0) {
                log_warning("Failed to get COMM, falling back to the command line.");
                comm = strv_join(argv + INFO_COMM + 1, " ");
        }

        if (get_process_exe(pid, &exe) < 0)
                log_warning("Failed to get EXE.");

        info[INFO_PID] = argv[INFO_PID + 1];
        info[INFO_UID] = argv[INFO_UID + 1];
        info[INFO_GID] = argv[INFO_GID + 1];
        info[INFO_SIGNAL] = argv[INFO_SIGNAL + 1];
        info[INFO_TIMESTAMP] = argv[INFO_TIMESTAMP + 1];
        info[INFO_COMM] = comm;
        info[INFO_EXE] = exe;

        if (cg_pid_get_unit(pid, &t) >= 0) {

                if (streq(t, SPECIAL_JOURNALD_SERVICE)) {
                        free(t);

                        /* If we are journald, we cut things short,
                         * don't write to the journal, but still
                         * create a coredump. */

                        if (arg_storage != COREDUMP_STORAGE_NONE)
                                arg_storage = COREDUMP_STORAGE_EXTERNAL;

                        r = save_external_coredump(info, uid, &filename, &coredump_fd, &coredump_size);
                        if (r < 0)
                                goto finish;

                        r = maybe_remove_external_coredump(filename, coredump_size);
                        if (r < 0)
                                goto finish;

                        log_info("Detected coredump of the journal daemon itself, diverted to %s.", filename);
                        goto finish;
                }

                core_unit = strjoina("COREDUMP_UNIT=", t);
                free(t);

        } else if (cg_pid_get_user_unit(pid, &t) >= 0) {
                core_unit = strjoina("COREDUMP_USER_UNIT=", t);
                free(t);
        }

        if (core_unit)
                IOVEC_SET_STRING(iovec[j++], core_unit);

        /* OK, now we know it's not the journal, hence we can make use
         * of it now. */
        log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
        log_open();

        core_pid = strjoina("COREDUMP_PID=", info[INFO_PID]);
        IOVEC_SET_STRING(iovec[j++], core_pid);

        core_uid = strjoina("COREDUMP_UID=", info[INFO_UID]);
        IOVEC_SET_STRING(iovec[j++], core_uid);

        core_gid = strjoina("COREDUMP_GID=", info[INFO_GID]);
        IOVEC_SET_STRING(iovec[j++], core_gid);

        core_signal = strjoina("COREDUMP_SIGNAL=", info[INFO_SIGNAL]);
        IOVEC_SET_STRING(iovec[j++], core_signal);

        if (sd_pid_get_session(pid, &t) >= 0) {
                core_session = strjoina("COREDUMP_SESSION=", t);
                free(t);

                IOVEC_SET_STRING(iovec[j++], core_session);
        }

        if (sd_pid_get_owner_uid(pid, &owner_uid) >= 0) {
                r = asprintf(&core_owner_uid,
                             "COREDUMP_OWNER_UID=" UID_FMT, owner_uid);
                if (r > 0)
                        IOVEC_SET_STRING(iovec[j++], core_owner_uid);
        }

        if (sd_pid_get_slice(pid, &t) >= 0) {
                core_slice = strjoina("COREDUMP_SLICE=", t);
                free(t);

                IOVEC_SET_STRING(iovec[j++], core_slice);
        }

        if (comm) {
                core_comm = strjoina("COREDUMP_COMM=", comm);
                IOVEC_SET_STRING(iovec[j++], core_comm);
        }

        if (exe) {
                core_exe = strjoina("COREDUMP_EXE=", exe);
                IOVEC_SET_STRING(iovec[j++], core_exe);
        }

        if (get_process_cmdline(pid, 0, false, &t) >= 0) {
                core_cmdline = strjoina("COREDUMP_CMDLINE=", t);
                free(t);

                IOVEC_SET_STRING(iovec[j++], core_cmdline);
        }

        if (cg_pid_get_path_shifted(pid, NULL, &t) >= 0) {
                core_cgroup = strjoina("COREDUMP_CGROUP=", t);
                free(t);

                IOVEC_SET_STRING(iovec[j++], core_cgroup);
        }

        if (compose_open_fds(pid, &t) >= 0) {
                core_open_fds = strappend("COREDUMP_OPEN_FDS=", t);
                free(t);

                if (core_open_fds)
                        IOVEC_SET_STRING(iovec[j++], core_open_fds);
        }

        p = procfs_file_alloca(pid, "status");
        if (read_full_file(p, &t, NULL) >= 0) {
                core_proc_status = strappend("COREDUMP_PROC_STATUS=", t);
                free(t);

                if (core_proc_status)
                        IOVEC_SET_STRING(iovec[j++], core_proc_status);
        }

        p = procfs_file_alloca(pid, "maps");
        if (read_full_file(p, &t, NULL) >= 0) {
                core_proc_maps = strappend("COREDUMP_PROC_MAPS=", t);
                free(t);

                if (core_proc_maps)
                        IOVEC_SET_STRING(iovec[j++], core_proc_maps);
        }

        p = procfs_file_alloca(pid, "limits");
        if (read_full_file(p, &t, NULL) >= 0) {
                core_proc_limits = strappend("COREDUMP_PROC_LIMITS=", t);
                free(t);

                if (core_proc_limits)
                        IOVEC_SET_STRING(iovec[j++], core_proc_limits);
        }

        p = procfs_file_alloca(pid, "cgroup");
        if (read_full_file(p, &t, NULL) >=0) {
                core_proc_cgroup = strappend("COREDUMP_PROC_CGROUP=", t);
                free(t);

                if (core_proc_cgroup)
                        IOVEC_SET_STRING(iovec[j++], core_proc_cgroup);
        }

        if (get_process_cwd(pid, &t) >= 0) {
                core_cwd = strjoina("COREDUMP_CWD=", t);
                free(t);

                IOVEC_SET_STRING(iovec[j++], core_cwd);
        }

        if (get_process_root(pid, &t) >= 0) {
                core_root = strjoina("COREDUMP_ROOT=", t);
                free(t);

                IOVEC_SET_STRING(iovec[j++], core_root);
        }

        if (get_process_environ(pid, &t) >= 0) {
                core_environ = strappend("COREDUMP_ENVIRON=", t);
                free(t);

                if (core_environ)
                        IOVEC_SET_STRING(iovec[j++], core_environ);
        }

        core_timestamp = strjoin("COREDUMP_TIMESTAMP=", info[INFO_TIMESTAMP], "000000", NULL);
        if (core_timestamp)
                IOVEC_SET_STRING(iovec[j++], core_timestamp);

        IOVEC_SET_STRING(iovec[j++], "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1");
        IOVEC_SET_STRING(iovec[j++], "PRIORITY=2");

        /* Vacuum before we write anything again */
        coredump_vacuum(-1, arg_keep_free, arg_max_use);

        /* Always stream the coredump to disk, if that's possible */
        r = save_external_coredump(info, uid, &filename, &coredump_fd, &coredump_size);
        if (r < 0)
                /* skip whole core dumping part */
                goto log;

        /* If we don't want to keep the coredump on disk, remove it
         * now, as later on we will lack the privileges for
         * it. However, we keep the fd to it, so that we can still
         * process it and log it. */
        r = maybe_remove_external_coredump(filename, coredump_size);
        if (r < 0)
                goto finish;
        if (r == 0) {
                const char *coredump_filename;

                coredump_filename = strjoina("COREDUMP_FILENAME=", filename);
                IOVEC_SET_STRING(iovec[j++], coredump_filename);
        }

        /* Vacuum again, but exclude the coredump we just created */
        coredump_vacuum(coredump_fd, arg_keep_free, arg_max_use);

        /* Now, let's drop privileges to become the user who owns the
         * segfaulted process and allocate the coredump memory under
         * the user's uid. This also ensures that the credentials
         * journald will see are the ones of the coredumping user,
         * thus making sure the user gets access to the core
         * dump. Let's also get rid of all capabilities, if we run as
         * root, we won't need them anymore. */
        r = drop_privileges(uid, gid, 0);
        if (r < 0) {
                log_error_errno(r, "Failed to drop privileges: %m");
                goto finish;
        }

#ifdef HAVE_ELFUTILS
        /* Try to get a strack trace if we can */
        if (coredump_size <= arg_process_size_max) {
                _cleanup_free_ char *stacktrace = NULL;

                r = coredump_make_stack_trace(coredump_fd, exe, &stacktrace);
                if (r >= 0)
                        core_message = strjoin("MESSAGE=Process ", info[INFO_PID], " (", comm, ") of user ", info[INFO_UID], " dumped core.\n\n", stacktrace, NULL);
                else if (r == -EINVAL)
                        log_warning("Failed to generate stack trace: %s", dwfl_errmsg(dwfl_errno()));
                else
                        log_warning_errno(r, "Failed to generate stack trace: %m");
        }

        if (!core_message)
#endif
log:
        core_message = strjoin("MESSAGE=Process ", info[INFO_PID], " (", comm, ") of user ", info[INFO_UID], " dumped core.", NULL);
        if (core_message)
                IOVEC_SET_STRING(iovec[j++], core_message);

        /* Optionally store the entire coredump in the journal */
        if (IN_SET(arg_storage, COREDUMP_STORAGE_JOURNAL, COREDUMP_STORAGE_BOTH) &&
            coredump_size <= arg_journal_size_max) {
                size_t sz = 0;

                /* Store the coredump itself in the journal */

                r = allocate_journal_field(coredump_fd, (size_t) coredump_size, &coredump_data, &sz);
                if (r >= 0) {
                        iovec[j].iov_base = coredump_data;
                        iovec[j].iov_len = sz;
                        j++;
                }
        }

        r = sd_journal_sendv(iovec, j);
        if (r < 0)
                log_error_errno(r, "Failed to log coredump: %m");

finish:
        return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}