PERF_RECORD_IP          = 1U << 0,
        PERF_RECORD_TID         = 1U << 1,
        PERF_RECORD_TIME        = 1U << 2,
-       PERF_RECORD_GROUP       = 1U << 3,
-       PERF_RECORD_CALLCHAIN   = 1U << 4,
+       PERF_RECORD_ADDR        = 1U << 3,
+       PERF_RECORD_GROUP       = 1U << 4,
+       PERF_RECORD_CALLCHAIN   = 1U << 5,
 };
 
 /*
         *      { u64                   ip;       } && PERF_RECORD_IP
         *      { u32                   pid, tid; } && PERF_RECORD_TID
         *      { u64                   time;     } && PERF_RECORD_TIME
+        *      { u64                   addr;     } && PERF_RECORD_ADDR
         *
         *      { u64                   nr;
         *        { u64 event, val; }   cnt[nr];  } && PERF_RECORD_GROUP
 extern void perf_counter_update_userpage(struct perf_counter *counter);
 
 extern int perf_counter_overflow(struct perf_counter *counter,
-                                int nmi, struct pt_regs *regs);
+                                int nmi, struct pt_regs *regs, u64 addr);
 /*
  * Return 1 for a software counter, 0 for a hardware counter
  */
                perf_event_type(&counter->hw_event) != PERF_TYPE_HARDWARE;
 }
 
-extern void perf_swcounter_event(u32, u64, int, struct pt_regs *);
+extern void perf_swcounter_event(u32, u64, int, struct pt_regs *, u64);
 
 extern void perf_counter_mmap(unsigned long addr, unsigned long len,
                              unsigned long pgoff, struct file *file);
 static inline int perf_counter_task_enable(void)       { return -EINVAL; }
 
 static inline void
-perf_swcounter_event(u32 event, u64 nr, int nmi, struct pt_regs *regs) { }
-
+perf_swcounter_event(u32 event, u64 nr, int nmi,
+                    struct pt_regs *regs, u64 addr)                    { }
 
 static inline void
 perf_counter_mmap(unsigned long addr, unsigned long len,
 
        update_context_time(ctx);
 
        regs = task_pt_regs(task);
-       perf_swcounter_event(PERF_COUNT_CONTEXT_SWITCHES, 1, 1, regs);
+       perf_swcounter_event(PERF_COUNT_CONTEXT_SWITCHES, 1, 1, regs, 0);
        __perf_counter_sched_out(ctx, cpuctx);
 
        cpuctx->task_ctx = NULL;
 }
 
 static void perf_counter_output(struct perf_counter *counter,
-                               int nmi, struct pt_regs *regs)
+                               int nmi, struct pt_regs *regs, u64 addr)
 {
        int ret;
        u64 record_type = counter->hw_event.record_type;
                header.size += sizeof(u64);
        }
 
+       if (record_type & PERF_RECORD_ADDR) {
+               header.type |= PERF_RECORD_ADDR;
+               header.size += sizeof(u64);
+       }
+
        if (record_type & PERF_RECORD_GROUP) {
                header.type |= PERF_RECORD_GROUP;
                header.size += sizeof(u64) +
        if (record_type & PERF_RECORD_TIME)
                perf_output_put(&handle, time);
 
+       if (record_type & PERF_RECORD_ADDR)
+               perf_output_put(&handle, addr);
+
        if (record_type & PERF_RECORD_GROUP) {
                struct perf_counter *leader, *sub;
                u64 nr = counter->nr_siblings;
  */
 
 int perf_counter_overflow(struct perf_counter *counter,
-                         int nmi, struct pt_regs *regs)
+                         int nmi, struct pt_regs *regs, u64 addr)
 {
        int events = atomic_read(&counter->event_limit);
        int ret = 0;
                        perf_counter_disable(counter);
        }
 
-       perf_counter_output(counter, nmi, regs);
+       perf_counter_output(counter, nmi, regs, addr);
        return ret;
 }
 
                regs = task_pt_regs(current);
 
        if (regs) {
-               if (perf_counter_overflow(counter, 0, regs))
+               if (perf_counter_overflow(counter, 0, regs, 0))
                        ret = HRTIMER_NORESTART;
        }
 
 }
 
 static void perf_swcounter_overflow(struct perf_counter *counter,
-                                   int nmi, struct pt_regs *regs)
+                                   int nmi, struct pt_regs *regs, u64 addr)
 {
        perf_swcounter_update(counter);
        perf_swcounter_set_period(counter);
-       if (perf_counter_overflow(counter, nmi, regs))
+       if (perf_counter_overflow(counter, nmi, regs, addr))
                /* soft-disable the counter */
                ;
 
 }
 
 static void perf_swcounter_add(struct perf_counter *counter, u64 nr,
-                              int nmi, struct pt_regs *regs)
+                              int nmi, struct pt_regs *regs, u64 addr)
 {
        int neg = atomic64_add_negative(nr, &counter->hw.count);
        if (counter->hw.irq_period && !neg)
-               perf_swcounter_overflow(counter, nmi, regs);
+               perf_swcounter_overflow(counter, nmi, regs, addr);
 }
 
 static void perf_swcounter_ctx_event(struct perf_counter_context *ctx,
                                     enum perf_event_types type, u32 event,
-                                    u64 nr, int nmi, struct pt_regs *regs)
+                                    u64 nr, int nmi, struct pt_regs *regs,
+                                    u64 addr)
 {
        struct perf_counter *counter;
 
        rcu_read_lock();
        list_for_each_entry_rcu(counter, &ctx->event_list, event_entry) {
                if (perf_swcounter_match(counter, type, event, regs))
-                       perf_swcounter_add(counter, nr, nmi, regs);
+                       perf_swcounter_add(counter, nr, nmi, regs, addr);
        }
        rcu_read_unlock();
 }
 }
 
 static void __perf_swcounter_event(enum perf_event_types type, u32 event,
-                                  u64 nr, int nmi, struct pt_regs *regs)
+                                  u64 nr, int nmi, struct pt_regs *regs,
+                                  u64 addr)
 {
        struct perf_cpu_context *cpuctx = &get_cpu_var(perf_cpu_context);
        int *recursion = perf_swcounter_recursion_context(cpuctx);
        (*recursion)++;
        barrier();
 
-       perf_swcounter_ctx_event(&cpuctx->ctx, type, event, nr, nmi, regs);
+       perf_swcounter_ctx_event(&cpuctx->ctx, type, event,
+                                nr, nmi, regs, addr);
        if (cpuctx->task_ctx) {
                perf_swcounter_ctx_event(cpuctx->task_ctx, type, event,
-                               nr, nmi, regs);
+                                        nr, nmi, regs, addr);
        }
 
        barrier();
        put_cpu_var(perf_cpu_context);
 }
 
-void perf_swcounter_event(u32 event, u64 nr, int nmi, struct pt_regs *regs)
+void
+perf_swcounter_event(u32 event, u64 nr, int nmi, struct pt_regs *regs, u64 addr)
 {
-       __perf_swcounter_event(PERF_TYPE_SOFTWARE, event, nr, nmi, regs);
+       __perf_swcounter_event(PERF_TYPE_SOFTWARE, event, nr, nmi, regs, addr);
 }
 
 static void perf_swcounter_read(struct perf_counter *counter)
        if (!regs)
                regs = task_pt_regs(current);
 
-       __perf_swcounter_event(PERF_TYPE_TRACEPOINT, event_id, 1, 1, regs);
+       __perf_swcounter_event(PERF_TYPE_TRACEPOINT, event_id, 1, 1, regs, 0);
 }
 
 extern int ftrace_profile_enable(int);