On Sun, May 06, 2018 at 06:49:35PM -0500, Josh Poimboeuf wrote:

> Deja vu.  Most of these are related to perf PEBS, similar to the
> following issue:
> 
>   b8000586c90b ("perf/x86/intel: Cure bogus unwind from PEBS entries")
> 
> This is basically the ORC version of that.  setup_pebs_sample_data() is
> assembling a franken-pt_regs which ORC isn't happy about.  RIP is
> inconsistent with some of the other registers (like RSP and RBP).
> 
> Peter, any ideas?

Urgh..

Something like so perhaps? It's a bit of a hack, but I couldn't quickly
think of something nicer.


diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c
index 707b2a96e516..86f0c15dcc2d 100644
--- a/arch/x86/events/intel/core.c
+++ b/arch/x86/events/intel/core.c
@@ -2997,6 +2997,9 @@ static int intel_pmu_hw_config(struct perf_event *event)
                }
                if (x86_pmu.pebs_aliases)
                        x86_pmu.pebs_aliases(event);
+
+               if (event->attr.sample_type & PERF_SAMPLE_CALLCHAIN)
+                       event->attr.sample_type |= 
__PERF_SAMPLE_CALLCHAIN_EARLY;
        }
 
        if (needs_branch_stack(event)) {
diff --git a/arch/x86/events/intel/ds.c b/arch/x86/events/intel/ds.c
index 8a10a045b57b..2115ac8336b4 100644
--- a/arch/x86/events/intel/ds.c
+++ b/arch/x86/events/intel/ds.c
@@ -1183,17 +1183,21 @@ static void setup_pebs_sample_data(struct perf_event 
*event,
                data->data_src.val = val;
        }
 
+       /*
+        * We must however always use iregs for the unwinder to stay sane; the
+        * record BP,SP,IP can point into thin air when the record is from a
+        * previous PMI context or an (I)RET happend between the record and
+        * PMI.
+        */
+       if (sample_type & PERF_SAMPLE_CALLCHAIN)
+               data->callchain = perf_callchain(event, iregs);
+
        /*
         * We use the interrupt regs as a base because the PEBS record does not
         * contain a full regs set, specifically it seems to lack segment
         * descriptors, which get used by things like user_mode().
         *
         * In the simple case fix up only the IP for PERF_SAMPLE_IP.
-        *
-        * We must however always use BP,SP from iregs for the unwinder to stay
-        * sane; the record BP,SP can point into thin air when the record is
-        * from a previous PMI context or an (I)RET happend between the record
-        * and PMI.
         */
        *regs = *iregs;
 
@@ -1212,15 +1216,8 @@ static void setup_pebs_sample_data(struct perf_event 
*event,
                regs->si = pebs->si;
                regs->di = pebs->di;
 
-               /*
-                * Per the above; only set BP,SP if we don't need callchains.
-                *
-                * XXX: does this make sense?
-                */
-               if (!(sample_type & PERF_SAMPLE_CALLCHAIN)) {
-                       regs->bp = pebs->bp;
-                       regs->sp = pebs->sp;
-               }
+               regs->bp = pebs->bp;
+               regs->sp = pebs->sp;
 
 #ifndef CONFIG_X86_32
                regs->r8 = pebs->r8;
diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_event.h
index b8e288a1f740..55b93cd0d48a 100644
--- a/include/uapi/linux/perf_event.h
+++ b/include/uapi/linux/perf_event.h
@@ -143,6 +143,8 @@ enum perf_event_sample_format {
        PERF_SAMPLE_PHYS_ADDR                   = 1U << 19,
 
        PERF_SAMPLE_MAX = 1U << 20,             /* non-ABI */
+
+       __PERF_SAMPLE_CALLCHAIN_EARLY           = 1UL << 63,
 };
 
 /*
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 67612ce359ad..27c9e0f99f30 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -6380,7 +6380,9 @@ void perf_prepare_sample(struct perf_event_header *header,
        if (sample_type & PERF_SAMPLE_CALLCHAIN) {
                int size = 1;
 
-               data->callchain = perf_callchain(event, regs);
+               if (!(sample_type & __PERF_SAMPLE_CALLCHAIN_EARLY))
+                       data->callchain = perf_callchain(event, regs);
+
                size += data->callchain->nr;
 
                header->size += size * sizeof(u64);

Reply via email to