Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 71ad0f5e authored by Jiri Olsa's avatar Jiri Olsa Committed by Arnaldo Carvalho de Melo
Browse files

perf tools: Support for DWARF CFI unwinding on post processing



This brings the support for DWARF cfi unwinding on perf post
processing. Call frame informations are retrieved and then passed
to libunwind that requests memory and register content from the
applications.

Adding unwind object to handle the user stack backtrace based
on the user register values and user stack dump.

The unwind object access the libunwind via remote interface
and provides to it all the necessary data to unwind the stack.

The unwind interface provides following function:
	unwind__get_entries

And callback (specified in above function) to retrieve
the backtrace entries:
	typedef int (*unwind_entry_cb_t)(struct unwind_entry *entry,
					 void *arg);

Signed-off-by: default avatarJiri Olsa <jolsa@redhat.com>
Original-patch-by: default avatarFrederic Weisbecker <fweisbec@gmail.com>
Cc: "Frank Ch. Eigler" <fche@redhat.com>
Cc: Arun Sharma <asharma@fb.com>
Cc: Benjamin Redelings <benjamin.redelings@nescent.org>
Cc: Corey Ashford <cjashfor@linux.vnet.ibm.com>
Cc: Cyrill Gorcunov <gorcunov@openvz.org>
Cc: Frank Ch. Eigler <fche@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Robert Richter <robert.richter@amd.com>
Cc: Stephane Eranian <eranian@google.com>
Cc: Tom Zanussi <tzanussi@gmail.com>
Cc: Ulrich Drepper <drepper@gmail.com>
Link: http://lkml.kernel.org/r/1344345647-11536-12-git-send-email-jolsa@redhat.com


[ Replaced use of perf_session by usage of perf_evsel ]
Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 0f6a3015
Loading
Loading
Loading
Loading
+2 −0
Original line number Original line Diff line number Diff line
@@ -334,6 +334,7 @@ LIB_H += util/target.h
LIB_H += util/rblist.h
LIB_H += util/rblist.h
LIB_H += util/intlist.h
LIB_H += util/intlist.h
LIB_H += util/perf_regs.h
LIB_H += util/perf_regs.h
LIB_H += util/unwind.h


LIB_OBJS += $(OUTPUT)util/abspath.o
LIB_OBJS += $(OUTPUT)util/abspath.o
LIB_OBJS += $(OUTPUT)util/alias.o
LIB_OBJS += $(OUTPUT)util/alias.o
@@ -547,6 +548,7 @@ else
	EXTLIBS += $(LIBUNWIND_LIBS)
	EXTLIBS += $(LIBUNWIND_LIBS)
	BASIC_CFLAGS := $(LIBUNWIND_CFLAGS) $(BASIC_CFLAGS)
	BASIC_CFLAGS := $(LIBUNWIND_CFLAGS) $(BASIC_CFLAGS)
	BASIC_LDFLAGS := $(LIBUNWIND_LDFLAGS) $(BASIC_LDFLAGS)
	BASIC_LDFLAGS := $(LIBUNWIND_LDFLAGS) $(BASIC_LDFLAGS)
	LIB_OBJS += $(OUTPUT)util/unwind.o
endif
endif


ifdef NO_NEWT
ifdef NO_NEWT
+3 −0
Original line number Original line Diff line number Diff line
@@ -2,4 +2,7 @@ ifndef NO_DWARF
PERF_HAVE_DWARF_REGS := 1
PERF_HAVE_DWARF_REGS := 1
LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o
LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o
endif
endif
ifndef NO_LIBUNWIND
LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind.o
endif
LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o
LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o
+111 −0
Original line number Original line Diff line number Diff line

#include <errno.h>
#include <libunwind.h>
#include "perf_regs.h"
#include "../../util/unwind.h"

#ifdef ARCH_X86_64
int unwind__arch_reg_id(int regnum)
{
	int id;

	switch (regnum) {
	case UNW_X86_64_RAX:
		id = PERF_REG_X86_AX;
		break;
	case UNW_X86_64_RDX:
		id = PERF_REG_X86_DX;
		break;
	case UNW_X86_64_RCX:
		id = PERF_REG_X86_CX;
		break;
	case UNW_X86_64_RBX:
		id = PERF_REG_X86_BX;
		break;
	case UNW_X86_64_RSI:
		id = PERF_REG_X86_SI;
		break;
	case UNW_X86_64_RDI:
		id = PERF_REG_X86_DI;
		break;
	case UNW_X86_64_RBP:
		id = PERF_REG_X86_BP;
		break;
	case UNW_X86_64_RSP:
		id = PERF_REG_X86_SP;
		break;
	case UNW_X86_64_R8:
		id = PERF_REG_X86_R8;
		break;
	case UNW_X86_64_R9:
		id = PERF_REG_X86_R9;
		break;
	case UNW_X86_64_R10:
		id = PERF_REG_X86_R10;
		break;
	case UNW_X86_64_R11:
		id = PERF_REG_X86_R11;
		break;
	case UNW_X86_64_R12:
		id = PERF_REG_X86_R12;
		break;
	case UNW_X86_64_R13:
		id = PERF_REG_X86_R13;
		break;
	case UNW_X86_64_R14:
		id = PERF_REG_X86_R14;
		break;
	case UNW_X86_64_R15:
		id = PERF_REG_X86_R15;
		break;
	case UNW_X86_64_RIP:
		id = PERF_REG_X86_IP;
		break;
	default:
		pr_err("unwind: invalid reg id %d\n", regnum);
		return -EINVAL;
	}

	return id;
}
#else
int unwind__arch_reg_id(int regnum)
{
	int id;

	switch (regnum) {
	case UNW_X86_EAX:
		id = PERF_REG_X86_AX;
		break;
	case UNW_X86_EDX:
		id = PERF_REG_X86_DX;
		break;
	case UNW_X86_ECX:
		id = PERF_REG_X86_CX;
		break;
	case UNW_X86_EBX:
		id = PERF_REG_X86_BX;
		break;
	case UNW_X86_ESI:
		id = PERF_REG_X86_SI;
		break;
	case UNW_X86_EDI:
		id = PERF_REG_X86_DI;
		break;
	case UNW_X86_EBP:
		id = PERF_REG_X86_BP;
		break;
	case UNW_X86_ESP:
		id = PERF_REG_X86_SP;
		break;
	case UNW_X86_EIP:
		id = PERF_REG_X86_IP;
		break;
	default:
		pr_err("unwind: invalid reg id %d\n", regnum);
		return -EINVAL;
	}

	return id;
}
#endif /* ARCH_X86_64 */
+9 −9
Original line number Original line Diff line number Diff line
@@ -69,8 +69,8 @@ static int perf_report__add_branch_hist_entry(struct perf_tool *tool,


	if ((sort__has_parent || symbol_conf.use_callchain)
	if ((sort__has_parent || symbol_conf.use_callchain)
	    && sample->callchain) {
	    && sample->callchain) {
		err = machine__resolve_callchain(machine, al->thread,
		err = machine__resolve_callchain(machine, evsel, al->thread,
						 sample->callchain, &parent);
						 sample, &parent);
		if (err)
		if (err)
			return err;
			return err;
	}
	}
@@ -140,8 +140,8 @@ static int perf_evsel__add_hist_entry(struct perf_evsel *evsel,
	struct hist_entry *he;
	struct hist_entry *he;


	if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) {
	if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) {
		err = machine__resolve_callchain(machine, al->thread,
		err = machine__resolve_callchain(machine, evsel, al->thread,
						 sample->callchain, &parent);
						 sample, &parent);
		if (err)
		if (err)
			return err;
			return err;
	}
	}
@@ -397,17 +397,17 @@ static int __cmd_report(struct perf_report *rep)
		desc);
		desc);
	}
	}


	if (dump_trace) {
		perf_session__fprintf_nr_events(session, stdout);
		goto out_delete;
	}

	if (verbose > 3)
	if (verbose > 3)
		perf_session__fprintf(session, stdout);
		perf_session__fprintf(session, stdout);


	if (verbose > 2)
	if (verbose > 2)
		perf_session__fprintf_dsos(session, stdout);
		perf_session__fprintf_dsos(session, stdout);


	if (dump_trace) {
		perf_session__fprintf_nr_events(session, stdout);
		goto out_delete;
	}

	nr_samples = 0;
	nr_samples = 0;
	list_for_each_entry(pos, &session->evlist->entries, node) {
	list_for_each_entry(pos, &session->evlist->entries, node) {
		struct hists *hists = &pos->hists;
		struct hists *hists = &pos->hists;
+2 −2
Original line number Original line Diff line number Diff line
@@ -380,7 +380,7 @@ static void print_sample_bts(union perf_event *event,
			printf(" ");
			printf(" ");
		else
		else
			printf("\n");
			printf("\n");
		perf_event__print_ip(event, sample, machine,
		perf_evsel__print_ip(evsel, event, sample, machine,
				     PRINT_FIELD(SYM), PRINT_FIELD(DSO),
				     PRINT_FIELD(SYM), PRINT_FIELD(DSO),
				     PRINT_FIELD(SYMOFFSET));
				     PRINT_FIELD(SYMOFFSET));
	}
	}
@@ -422,7 +422,7 @@ static void process_event(union perf_event *event, struct perf_sample *sample,
			printf(" ");
			printf(" ");
		else
		else
			printf("\n");
			printf("\n");
		perf_event__print_ip(event, sample, machine,
		perf_evsel__print_ip(evsel, event, sample, machine,
				     PRINT_FIELD(SYM), PRINT_FIELD(DSO),
				     PRINT_FIELD(SYM), PRINT_FIELD(DSO),
				     PRINT_FIELD(SYMOFFSET));
				     PRINT_FIELD(SYMOFFSET));
	}
	}
Loading