perf/urgent fixes:

- 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>
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABAgAGBQJWsjJzAAoJENZQFvNTUqpAF2EP/2UJGz/mi7O3wu90YO7BnglD
 WizS/Y4fTLDfoz9+hwiUscHMvBOpAYMRbGX73AyHCP5qPsv1fRyW5jPCyCqpvDWB
 TU86CX0t9CEXAj3mKTwShqIXiY9Hmf0lOwxAxY+Y5I12utirqHzZreilBhNvHStz
 ESYXpTKsDNdU08Zu7nLmKqIlFLnRvY+7sL55+rgcw7DWaIcivpAF8b8RX7iJyoJk
 fL7dkebXDtZvQpBZ4A8TniACjqebfpg1BSiZ7c9NDIs7YMB+2VPDzXrySP2Oq3q6
 u8rZtwn8/0idZ5Es2LWU68QXJL0Z6q7p74BZ+/IO1jSTviegu8CQTfIHRfyx+ur4
 IZroUuEPDz9tFw7q8tUt/D48Qbh7rOIFBYUHtbq9e0g1WfW2g0NzP/EseNQxkica
 uZdfn98cHZyeGiNLhRAjqTwGmZTlV7EoNh6282i7PwyJ9J5nOs36f3Tuo1bekVp+
 qtugNbE2xebwwCiBSAHbsQcIrKnyL+bcgSrDzKAP5kBz9r58TQad+CUNQ/IHyhdr
 q66RYEy3cdmotcPKtK5jxNMYoSoJzlGEpX3FKXZNHkpRIkNp1vZA6MlSIiHOo/A8
 eUg6O55XBRJLYdZ/Q2Vb1t1X83g2789o4tgW0tOUtwBwCW7AIQq7w2m08aUCbQf5
 2/HaTdhyxMx6ra34dzS1
 =0cG5
 -----END PGP SIGNATURE-----

Merge tag 'perf-urgent-for-mingo' of git://git.kernel.org/pub/scm/linux/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>
This commit is contained in:
Ingo Molnar 2016-02-04 08:55:00 +01:00
commit 9a969403c3
4 changed files with 53 additions and 26 deletions

View File

@ -2068,6 +2068,15 @@ int intel_pt_process_auxtrace_info(union perf_event *event,
err = -ENOMEM; err = -ENOMEM;
goto err_free_queues; 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); err = thread__set_comm(pt->unknown_thread, "unknown", 0);
if (err) if (err)
goto err_delete_thread; goto err_delete_thread;

View File

@ -399,6 +399,9 @@ static void tracepoint_error(struct parse_events_error *e, int err,
{ {
char help[BUFSIZ]; char help[BUFSIZ];
if (!e)
return;
/* /*
* We get error directly from syscall errno ( > 0), * We get error directly from syscall errno ( > 0),
* or from encoded pointer's error ( < 0). * or from encoded pointer's error ( < 0).

View File

@ -686,8 +686,9 @@ static int call_probe_finder(Dwarf_Die *sc_die, struct probe_finder *pf)
pf->fb_ops = NULL; pf->fb_ops = NULL;
#if _ELFUTILS_PREREQ(0, 142) #if _ELFUTILS_PREREQ(0, 142)
} else if (nops == 1 && pf->fb_ops[0].atom == DW_OP_call_frame_cfa && } else if (nops == 1 && pf->fb_ops[0].atom == DW_OP_call_frame_cfa &&
pf->cfi != NULL) { (pf->cfi_eh != NULL || pf->cfi_dbg != NULL)) {
if (dwarf_cfi_addrframe(pf->cfi, pf->addr, &frame) != 0 || 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) { dwarf_frame_cfa(frame, &pf->fb_ops, &nops) != 0) {
pr_warning("Failed to get call frame on 0x%jx\n", pr_warning("Failed to get call frame on 0x%jx\n",
(uintmax_t)pf->addr); (uintmax_t)pf->addr);
@ -1015,8 +1016,7 @@ static int pubname_search_cb(Dwarf *dbg, Dwarf_Global *gl, void *data)
return DWARF_CB_OK; return DWARF_CB_OK;
} }
/* Find probe points from debuginfo */ static int debuginfo__find_probe_location(struct debuginfo *dbg,
static int debuginfo__find_probes(struct debuginfo *dbg,
struct probe_finder *pf) struct probe_finder *pf)
{ {
struct perf_probe_point *pp = &pf->pev->point; struct perf_probe_point *pp = &pf->pev->point;
@ -1025,27 +1025,6 @@ static int debuginfo__find_probes(struct debuginfo *dbg,
Dwarf_Die *diep; Dwarf_Die *diep;
int ret = 0; 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; off = 0;
pf->lcache = intlist__new(NULL); pf->lcache = intlist__new(NULL);
if (!pf->lcache) if (!pf->lcache)
@ -1108,6 +1087,39 @@ static int debuginfo__find_probes(struct debuginfo *dbg,
return ret; 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 local_vars_finder {
struct probe_finder *pf; struct probe_finder *pf;
struct perf_probe_arg *args; struct perf_probe_arg *args;

View File

@ -76,7 +76,10 @@ struct probe_finder {
/* For variable searching */ /* For variable searching */
#if _ELFUTILS_PREREQ(0, 142) #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 #endif
Dwarf_Op *fb_ops; /* Frame base attribute */ Dwarf_Op *fb_ops; /* Frame base attribute */
struct perf_probe_arg *pvar; /* Current target variable */ struct perf_probe_arg *pvar; /* Current target variable */