Skip to content

Commit

Permalink
Merge tag 'perf-urgent-for-mingo' of git://git.kernel.org/pub/scm/lin…
Browse files Browse the repository at this point in the history
…ux/kernel/git/acme/linux into perf/urgent

Pull perf/urgent fixes from Arnaldo Carvalho de Melo:

 - tracepoint_error() can receive e=NULL, robustify it, fixes a problem noticed
   with a very specific combination: Machine with Intel PT (e.g. Broadwell),
   kernel with no perf_event_attr.context_switch feature (e.g. 4.2) and unreadable
   tracefs (for instance !root users), making the fallback from
   perf_event_attr.context_switch to the sched:sched_switch tracepoint to fail
   reading its info from tracefs, fix it. (Adrian Hunter)

 - Fix segfault in intel PT, by making it follow the 'struct thread' lifetime cycle
   checking expectations, noticed for instance, when processing perf.data files with
   Intel PT data using 'perf script' and when exiting 'perf report' (Adrian Hunter)

 - Fix CFI usage from .eh_frame and .debug_frame, which sometimes requires that we
   fallback from .eh_frame to .debug_frame in architectures such as PowerPC (Hemant Kumar)

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
  • Loading branch information
Ingo Molnar committed Feb 4, 2016
2 parents b37a05c + 270bde1 commit 9a96940
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 26 deletions.
9 changes: 9 additions & 0 deletions tools/perf/util/intel-pt.c
Original file line number Diff line number Diff line change
Expand Up @@ -2068,6 +2068,15 @@ int intel_pt_process_auxtrace_info(union perf_event *event,
err = -ENOMEM;
goto err_free_queues;
}

/*
* Since this thread will not be kept in any rbtree not in a
* list, initialize its list node so that at thread__put() the
* current thread lifetime assuption is kept and we don't segfault
* at list_del_init().
*/
INIT_LIST_HEAD(&pt->unknown_thread->node);

err = thread__set_comm(pt->unknown_thread, "unknown", 0);
if (err)
goto err_delete_thread;
Expand Down
3 changes: 3 additions & 0 deletions tools/perf/util/parse-events.c
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,9 @@ static void tracepoint_error(struct parse_events_error *e, int err,
{
char help[BUFSIZ];

if (!e)
return;

/*
* We get error directly from syscall errno ( > 0),
* or from encoded pointer's error ( < 0).
Expand Down
62 changes: 37 additions & 25 deletions tools/perf/util/probe-finder.c
Original file line number Diff line number Diff line change
Expand Up @@ -686,8 +686,9 @@ static int call_probe_finder(Dwarf_Die *sc_die, struct probe_finder *pf)
pf->fb_ops = NULL;
#if _ELFUTILS_PREREQ(0, 142)
} else if (nops == 1 && pf->fb_ops[0].atom == DW_OP_call_frame_cfa &&
pf->cfi != NULL) {
if (dwarf_cfi_addrframe(pf->cfi, pf->addr, &frame) != 0 ||
(pf->cfi_eh != NULL || pf->cfi_dbg != NULL)) {
if ((dwarf_cfi_addrframe(pf->cfi_eh, pf->addr, &frame) != 0 &&
(dwarf_cfi_addrframe(pf->cfi_dbg, pf->addr, &frame) != 0)) ||
dwarf_frame_cfa(frame, &pf->fb_ops, &nops) != 0) {
pr_warning("Failed to get call frame on 0x%jx\n",
(uintmax_t)pf->addr);
Expand Down Expand Up @@ -1015,8 +1016,7 @@ static int pubname_search_cb(Dwarf *dbg, Dwarf_Global *gl, void *data)
return DWARF_CB_OK;
}

/* Find probe points from debuginfo */
static int debuginfo__find_probes(struct debuginfo *dbg,
static int debuginfo__find_probe_location(struct debuginfo *dbg,
struct probe_finder *pf)
{
struct perf_probe_point *pp = &pf->pev->point;
Expand All @@ -1025,27 +1025,6 @@ static int debuginfo__find_probes(struct debuginfo *dbg,
Dwarf_Die *diep;
int ret = 0;

#if _ELFUTILS_PREREQ(0, 142)
Elf *elf;
GElf_Ehdr ehdr;
GElf_Shdr shdr;

/* Get the call frame information from this dwarf */
elf = dwarf_getelf(dbg->dbg);
if (elf == NULL)
return -EINVAL;

if (gelf_getehdr(elf, &ehdr) == NULL)
return -EINVAL;

if (elf_section_by_name(elf, &ehdr, &shdr, ".eh_frame", NULL) &&
shdr.sh_type == SHT_PROGBITS) {
pf->cfi = dwarf_getcfi_elf(elf);
} else {
pf->cfi = dwarf_getcfi(dbg->dbg);
}
#endif

off = 0;
pf->lcache = intlist__new(NULL);
if (!pf->lcache)
Expand Down Expand Up @@ -1108,6 +1087,39 @@ static int debuginfo__find_probes(struct debuginfo *dbg,
return ret;
}

/* Find probe points from debuginfo */
static int debuginfo__find_probes(struct debuginfo *dbg,
struct probe_finder *pf)
{
int ret = 0;

#if _ELFUTILS_PREREQ(0, 142)
Elf *elf;
GElf_Ehdr ehdr;
GElf_Shdr shdr;

if (pf->cfi_eh || pf->cfi_dbg)
return debuginfo__find_probe_location(dbg, pf);

/* Get the call frame information from this dwarf */
elf = dwarf_getelf(dbg->dbg);
if (elf == NULL)
return -EINVAL;

if (gelf_getehdr(elf, &ehdr) == NULL)
return -EINVAL;

if (elf_section_by_name(elf, &ehdr, &shdr, ".eh_frame", NULL) &&
shdr.sh_type == SHT_PROGBITS)
pf->cfi_eh = dwarf_getcfi_elf(elf);

pf->cfi_dbg = dwarf_getcfi(dbg->dbg);
#endif

ret = debuginfo__find_probe_location(dbg, pf);
return ret;
}

struct local_vars_finder {
struct probe_finder *pf;
struct perf_probe_arg *args;
Expand Down
5 changes: 4 additions & 1 deletion tools/perf/util/probe-finder.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,10 @@ struct probe_finder {

/* For variable searching */
#if _ELFUTILS_PREREQ(0, 142)
Dwarf_CFI *cfi; /* Call Frame Information */
/* Call Frame Information from .eh_frame */
Dwarf_CFI *cfi_eh;
/* Call Frame Information from .debug_frame */
Dwarf_CFI *cfi_dbg;
#endif
Dwarf_Op *fb_ops; /* Frame base attribute */
struct perf_probe_arg *pvar; /* Current target variable */
Expand Down

0 comments on commit 9a96940

Please sign in to comment.