lkml.org 
[lkml]   [2012]   [Apr]   [23]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    /
    Date
    SubjectRe: [PATCH 03/16] perf: Add ability to dump user regs
    From
    On Tue, Apr 17, 2012 at 1:17 PM, Jiri Olsa <jolsa@redhat.com> wrote:
    > Add new attr->user_regs bitmap that lets a user choose a set
    > of user registers to dump to the sample. The layout of this
    > bitmap is described in asm/perf_regs.h for archs that
    > support register dump.
    >
    > The perf syscall will fail if attr->user_regs is non zero.
    >
    > The register value here are those of the user space context as
    > it was before the user entered the kernel for whatever reason
    > (syscall, irq, exception, or a PMI happening in userspace).
    >
    > This is going to be useful to bring Dwarf CFI based stack unwinding
    > on top of samples.
    >
    > TODO handle compat tasks
    >
    > Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
    > Signed-off-by: Jiri Olsa <jolsa@redhat.com>
    > ---
    >  include/linux/perf_event.h |    8 +++++
    >  kernel/events/core.c       |   63 ++++++++++++++++++++++++++++++++++++++++++++
    >  2 files changed, 71 insertions(+), 0 deletions(-)
    >
    > diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
    > index ddbb6a9..c63b807 100644
    > --- a/include/linux/perf_event.h
    > +++ b/include/linux/perf_event.h
    > @@ -272,6 +272,12 @@ struct perf_event_attr {
    >                __u64           config2; /* extension of config1 */
    >        };
    >        __u64   branch_sample_type; /* enum branch_sample_type */
    > +
    > +       /*
    > +        * Arch specific mask that defines a set of user regs to dump on
    > +        * samples. See asm/perf_regs.h for details.
    > +        */
    > +       __u64                   user_regs;
    >  };
    >
    Don't like the name of the field too much. You be more explicit.
    Something like user_sample_regs.

    >  /*
    > @@ -608,6 +614,7 @@ struct perf_guest_info_callbacks {
    >  #include <linux/atomic.h>
    >  #include <linux/sysfs.h>
    >  #include <asm/local.h>
    > +#include <asm/perf_regs.h>
    >
    >  #define PERF_MAX_STACK_DEPTH           255
    >
    > @@ -1130,6 +1137,7 @@ struct perf_sample_data {
    >        struct perf_callchain_entry     *callchain;
    >        struct perf_raw_record          *raw;
    >        struct perf_branch_stack        *br_stack;
    > +       struct pt_regs                  *uregs;
    >  };
    >
    >  static inline void perf_sample_data_init(struct perf_sample_data *data, u64 addr)
    > diff --git a/kernel/events/core.c b/kernel/events/core.c
    > index a6a9ec4..9f29fc3 100644
    > --- a/kernel/events/core.c
    > +++ b/kernel/events/core.c
    > @@ -3751,6 +3751,37 @@ int perf_unregister_guest_info_callbacks(struct perf_guest_info_callbacks *cbs)
    >  }
    >  EXPORT_SYMBOL_GPL(perf_unregister_guest_info_callbacks);
    >
    > +static void
    > +perf_output_sample_regs(struct perf_output_handle *handle,
    > +                       struct pt_regs *regs, u64 mask)
    > +{
    > +       int i = 0;
    > +
    > +       do {
    > +               u64 val;
    > +
    > +               if (mask & 1) {
    > +                       val = perf_reg_value(regs, i);
    > +                       perf_output_put(handle, val);
    > +               }
    > +
    > +               mask >>= 1;
    > +               i++;
    > +       } while (mask);
    > +}
    > +
    > +static struct pt_regs *perf_sample_uregs(struct pt_regs *regs)
    > +{
    > +       if (!user_mode(regs)) {
    > +               if (current->mm)
    > +                       regs = task_pt_regs(current);
    > +               else
    > +                       regs = NULL;
    > +       }
    > +
    > +       return regs;
    > +}
    > +
    You are assuming the user app is running the same ABI than that of the
    kernel. That's not correct on X86 and possibly other architectures.

    >  static void __perf_event_header__init_id(struct perf_event_header *header,
    >                                         struct perf_sample_data *data,
    >                                         struct perf_event *event)
    > @@ -4011,6 +4042,21 @@ void perf_output_sample(struct perf_output_handle *handle,
    >                        perf_output_put(handle, nr);
    >                }
    >        }
    > +
    > +       if (event->attr.user_regs) {
    > +               u64 id;
    > +
    > +               /*
    > +                * If there are no regs to dump, notice it through a
    > +                * PERF_REGS_VERSION_NONE version.
    > +                */
    > +               id = data->uregs ? perf_reg_version() : PERF_REGS_VERSION_NONE;
    > +               perf_output_put(handle, id);
    > +
    > +               if (id)
    > +                       perf_output_sample_regs(handle, data->uregs,
    > +                                               event->attr.user_regs);
    > +       }
    >  }
    >
    >  void perf_prepare_sample(struct perf_event_header *header,
    > @@ -4062,6 +4108,16 @@ void perf_prepare_sample(struct perf_event_header *header,
    >                }
    >                header->size += size;
    >        }
    > +
    > +       if (event->attr.user_regs) {
    > +               int size = sizeof(u64); /* the version size */
    > +
    > +               data->uregs = perf_sample_uregs(regs);
    > +               if (data->uregs)
    > +                       size += hweight64(event->attr.user_regs) * sizeof(u64);
    > +
    > +               header->size += size;
    > +       }
    >  }
    >
    >  static void perf_event_output(struct perf_event *event,
    > @@ -6112,6 +6168,13 @@ static int perf_copy_attr(struct perf_event_attr __user *uattr,
    >                        attr->branch_sample_type = mask;
    >                }
    >        }
    > +
    > +       /*
    > +        * Don't let throught invalid register mask (i.e. the architecture
    > +        * does not support register dump at all).
    > +        */
    > +       ret = perf_reg_validate(attr->user_regs);
    > +
    Again, how do you deal with 32-bit apps vs. 64-bit kernel?

    >  out:
    >        return ret;
    >
    > --
    > 1.7.7.6
    >
    --
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

    \
     
     \ /
      Last update: 2012-04-23 12:19    [W:0.050 / U:0.364 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site