Exemple #1
0
int
process_clone(struct Process *retp, struct Process *proc, pid_t pid)
{
	if (process_bare_init(retp, proc->filename, pid, 0) < 0) {
	fail1:
		fprintf(stderr, "failed to clone process %d->%d : %s\n",
			proc->pid, pid, strerror(errno));
		return -1;
	}

	retp->tracesysgood = proc->tracesysgood;
	retp->e_machine = proc->e_machine;
	retp->e_class = proc->e_class;

	/* For non-leader processes, that's all we need to do.  */
	if (retp->leader != retp)
		return 0;

	/* Clone symbols first so that we can clone and relink
	 * breakpoints.  */
	struct library *lib;
	struct library **nlibp = &retp->libraries;
	for (lib = proc->leader->libraries; lib != NULL; lib = lib->next) {
		*nlibp = malloc(sizeof(**nlibp));
		if (*nlibp == NULL
		    || library_clone(*nlibp, lib) < 0) {
		fail2:
			process_bare_destroy(retp, 0);

			/* Error when cloning.  Unroll what was done.  */
			for (lib = retp->libraries; lib != NULL; ) {
				struct library *next = lib->next;
				library_destroy(lib);
				free(lib);
				lib = next;
			}
			goto fail1;
		}

		nlibp = &(*nlibp)->next;
	}

	/* Now clone breakpoints.  Symbol relinking is done in
	 * clone_single_bp.  */
	struct clone_single_bp_data data = {
		.old_proc = proc,
		.new_proc = retp,
		.error = 0,
	};
	dict_apply_to_all(proc->leader->breakpoints, &clone_single_bp, &data);
	if (data.error < 0)
		goto fail2;

	/* And finally the call stack.  */
	/* XXX clearly the callstack handling should be moved to a
	 * separate module and this whole business extracted to
	 * callstack_clone, or callstack_element_clone.  */
	memcpy(retp->callstack, proc->callstack, sizeof(retp->callstack));
	retp->callstack_depth = proc->callstack_depth;

	size_t i;
	for (i = 0; i < retp->callstack_depth; ++i) {
		struct callstack_element *elem = &retp->callstack[i];
		struct fetch_context *ctx = elem->fetch_context;
		if (ctx != NULL) {
			struct fetch_context *nctx = fetch_arg_clone(retp, ctx);
			if (nctx == NULL) {
				size_t j;
			fail3:
				for (j = 0; j < i; ++j) {
					nctx = elem->fetch_context;
					fetch_arg_done(nctx);
					elem->fetch_context = NULL;
				}
				goto fail2;
			}
			elem->fetch_context = nctx;
		}

		struct value_dict *args = elem->arguments;
		if (args != NULL) {
			struct value_dict *nargs = malloc(sizeof(*nargs));
			if (nargs == NULL
			    || val_dict_clone(nargs, args) < 0) {
				size_t j;
				for (j = 0; j < i; ++j) {
					nargs = elem->arguments;
					val_dict_destroy(nargs);
					free(nargs);
					elem->arguments = NULL;
				}

				/* Pretend that this round went well,
				 * so that fail3 frees I-th
				 * fetch_context.  */
				++i;
				goto fail3;
			}
			elem->arguments = nargs;
		}

		/* If it's not a syscall, we need to find the
		 * corresponding library symbol in the cloned
		 * library.  */
		if (!elem->is_syscall && elem->c_un.libfunc != NULL) {
			struct library_symbol *libfunc = elem->c_un.libfunc;
			int rc = proc_find_symbol(retp, libfunc,
						  NULL, &elem->c_un.libfunc);
			assert(rc == 0);
		}
	}

	/* At this point, retp is fully initialized, except for OS and
	 * arch parts, and we can call private_process_destroy.  */
	if (os_process_clone(retp, proc) < 0) {
		private_process_destroy(retp, 0);
		return -1;
	}
	if (arch_process_clone(retp, proc) < 0) {
		os_process_destroy(retp);
		private_process_destroy(retp, 0);
		return -1;
	}

	return 0;
}

static int
open_one_pid(pid_t pid)
{
	Process *proc;
	char *filename;
	debug(DEBUG_PROCESS, "open_one_pid(pid=%d)", pid);

	/* Get the filename first.  Should the trace_pid fail, we can
	 * easily free it, untracing is more work.  */
	if ((filename = pid2name(pid)) == NULL
	    || trace_pid(pid) < 0) {
	fail:
		free(filename);
		return -1;
	}

	proc = open_program(filename, pid);
	if (proc == NULL)
		goto fail;
	free(filename);
	trace_set_options(proc);

	return 0;
}
void
output_left(enum tof type, struct process *proc,
            struct library_symbol *libsym)
{
    assert(! options.summary);

    if (current_proc) {
        fprintf(options.output, " <unfinished ...>\n");
        current_column = 0;
    }
    current_proc = proc;
    current_depth = proc->callstack_depth;
    begin_of_line(proc, type == LT_TOF_FUNCTION, 1);
    if (!options.hide_caller && libsym->lib != NULL
            && libsym->plt_type != LS_TOPLT_NONE)
        /* We don't terribly mind failing this.  */
        account_output(&current_column,
                       fprintf(options.output, "%s->",
                               libsym->lib->soname));

    const char *name = libsym->name;
#ifdef USE_DEMANGLE
    if (options.demangle)
        name = my_demangle(libsym->name);
#endif
    if (account_output(&current_column,
                       fprintf(options.output, "%s", name)) < 0)
        return;

    if (libsym->lib != NULL
            && libsym->lib->type != LT_LIBTYPE_MAIN
            && libsym->plt_type == LS_TOPLT_NONE
            && account_output(&current_column,
                              fprintf(options.output, "@%s",
                                      libsym->lib->soname)) < 0)
        /* We do mind failing this though.  */
        return;

    account_output(&current_column, fprintf(options.output, "("));

    struct prototype *func = lookup_symbol_prototype(proc, libsym);
    if (func == NULL) {
fail:
        account_output(&current_column, fprintf(options.output, "???"));
        return;
    }

    struct fetch_context *context = fetch_arg_init(type, proc,
                                    func->return_info);
    if (context == NULL)
        goto fail;

    struct value_dict *arguments = malloc(sizeof(*arguments));
    if (arguments == NULL) {
        fetch_arg_done(context);
        goto fail;
    }
    val_dict_init(arguments);

    ssize_t params_left = -1;
    int need_delim = 0;
    if (fetch_params(type, proc, context, arguments, func, &params_left) < 0
            || output_params(arguments, 0, params_left, &need_delim) < 0) {
        val_dict_destroy(arguments);
        fetch_arg_done(context);
        arguments = NULL;
        context = NULL;
    }

    struct callstack_element *stel
            = &proc->callstack[proc->callstack_depth - 1];
    stel->fetch_context = context;
    stel->arguments = arguments;
    stel->out.params_left = params_left;
    stel->out.need_delim = need_delim;
}