OSDN Git Service

Merge branch 'perf/urgent' into perf/core
authorIngo Molnar <mingo@kernel.org>
Thu, 27 Feb 2014 11:41:17 +0000 (12:41 +0100)
committerIngo Molnar <mingo@kernel.org>
Thu, 27 Feb 2014 11:41:17 +0000 (12:41 +0100)
Merge the latest fixes before queueing up new changes.

Signed-off-by: Ingo Molnar <mingo@kernel.org>
62 files changed:
arch/x86/include/asm/nmi.h
arch/x86/kernel/cpu/perf_event_intel_uncore.c
arch/x86/kernel/cpu/perf_event_intel_uncore.h
arch/x86/kernel/cpu/perf_event_p4.c
arch/x86/kernel/nmi.c
include/linux/irq_work.h
include/linux/pci_ids.h
kernel/events/core.c
kernel/irq_work.c
tools/include/linux/hash.h [new file with mode: 0644]
tools/lib/api/Makefile
tools/lib/api/fs/fs.c [moved from tools/perf/util/fs.c with 91% similarity]
tools/lib/api/fs/fs.h [moved from tools/perf/util/include/linux/magic.h with 50% similarity]
tools/perf/MANIFEST
tools/perf/Makefile.perf
tools/perf/arch/arm/Makefile
tools/perf/arch/arm/util/unwind-libunwind.c [moved from tools/perf/arch/arm/util/unwind.c with 95% similarity]
tools/perf/arch/x86/Makefile
tools/perf/arch/x86/include/perf_regs.h
tools/perf/arch/x86/tests/dwarf-unwind.c [new file with mode: 0644]
tools/perf/arch/x86/tests/regs_load.S [new file with mode: 0644]
tools/perf/arch/x86/util/unwind-libunwind.c [moved from tools/perf/arch/x86/util/unwind.c with 95% similarity]
tools/perf/builtin-inject.c
tools/perf/builtin-probe.c
tools/perf/builtin-record.c
tools/perf/builtin-report.c
tools/perf/builtin-top.c
tools/perf/config/Makefile
tools/perf/perf.h
tools/perf/tests/builtin-test.c
tools/perf/tests/dwarf-unwind.c [new file with mode: 0644]
tools/perf/tests/parse-events.c
tools/perf/tests/sample-parsing.c
tools/perf/tests/tests.h
tools/perf/util/cpumap.c
tools/perf/util/dso.h
tools/perf/util/event.h
tools/perf/util/evsel.c
tools/perf/util/fs.h [deleted file]
tools/perf/util/hist.c
tools/perf/util/include/linux/hash.h [deleted file]
tools/perf/util/include/linux/list.h
tools/perf/util/include/linux/prefetch.h [deleted file]
tools/perf/util/machine.c
tools/perf/util/machine.h
tools/perf/util/map.h
tools/perf/util/perf_regs.c [new file with mode: 0644]
tools/perf/util/perf_regs.h
tools/perf/util/pmu.c
tools/perf/util/probe-event.c
tools/perf/util/probe-event.h
tools/perf/util/probe-finder.c
tools/perf/util/probe-finder.h
tools/perf/util/python-ext-sources
tools/perf/util/record.c
tools/perf/util/session.c
tools/perf/util/symbol.c
tools/perf/util/symbol.h
tools/perf/util/trace-event-parse.c
tools/perf/util/unwind-libunwind.c [moved from tools/perf/util/unwind.c with 92% similarity]
tools/perf/util/unwind.h
tools/perf/util/util.c

index 86f9301..5f2fc44 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef _ASM_X86_NMI_H
 #define _ASM_X86_NMI_H
 
+#include <linux/irq_work.h>
 #include <linux/pm.h>
 #include <asm/irq.h>
 #include <asm/io.h>
@@ -38,6 +39,8 @@ typedef int (*nmi_handler_t)(unsigned int, struct pt_regs *);
 struct nmiaction {
        struct list_head        list;
        nmi_handler_t           handler;
+       u64                     max_duration;
+       struct irq_work         irq_work;
        unsigned long           flags;
        const char              *name;
 };
index c88f7f4..b262c61 100644 (file)
@@ -66,6 +66,47 @@ DEFINE_UNCORE_FORMAT_ATTR(mask_vnw, mask_vnw, "config2:3-4");
 DEFINE_UNCORE_FORMAT_ATTR(mask0, mask0, "config2:0-31");
 DEFINE_UNCORE_FORMAT_ATTR(mask1, mask1, "config2:32-63");
 
+static void uncore_pmu_start_hrtimer(struct intel_uncore_box *box);
+static void uncore_pmu_cancel_hrtimer(struct intel_uncore_box *box);
+static void uncore_perf_event_update(struct intel_uncore_box *box, struct perf_event *event);
+static void uncore_pmu_event_read(struct perf_event *event);
+
+static struct intel_uncore_pmu *uncore_event_to_pmu(struct perf_event *event)
+{
+       return container_of(event->pmu, struct intel_uncore_pmu, pmu);
+}
+
+static struct intel_uncore_box *
+uncore_pmu_to_box(struct intel_uncore_pmu *pmu, int cpu)
+{
+       struct intel_uncore_box *box;
+
+       box = *per_cpu_ptr(pmu->box, cpu);
+       if (box)
+               return box;
+
+       raw_spin_lock(&uncore_box_lock);
+       list_for_each_entry(box, &pmu->box_list, list) {
+               if (box->phys_id == topology_physical_package_id(cpu)) {
+                       atomic_inc(&box->refcnt);
+                       *per_cpu_ptr(pmu->box, cpu) = box;
+                       break;
+               }
+       }
+       raw_spin_unlock(&uncore_box_lock);
+
+       return *per_cpu_ptr(pmu->box, cpu);
+}
+
+static struct intel_uncore_box *uncore_event_to_box(struct perf_event *event)
+{
+       /*
+        * perf core schedules event on the basis of cpu, uncore events are
+        * collected by one of the cpus inside a physical package.
+        */
+       return uncore_pmu_to_box(uncore_event_to_pmu(event), smp_processor_id());
+}
+
 static u64 uncore_msr_read_counter(struct intel_uncore_box *box, struct perf_event *event)
 {
        u64 count;
@@ -1639,6 +1680,345 @@ static struct intel_uncore_type *snb_msr_uncores[] = {
        &snb_uncore_cbox,
        NULL,
 };
+
+enum {
+       SNB_PCI_UNCORE_IMC,
+};
+
+static struct uncore_event_desc snb_uncore_imc_events[] = {
+       INTEL_UNCORE_EVENT_DESC(data_reads,  "event=0x01"),
+       INTEL_UNCORE_EVENT_DESC(data_reads.scale, "6.103515625e-5"),
+       INTEL_UNCORE_EVENT_DESC(data_reads.unit, "MiB"),
+
+       INTEL_UNCORE_EVENT_DESC(data_writes, "event=0x02"),
+       INTEL_UNCORE_EVENT_DESC(data_writes.scale, "6.103515625e-5"),
+       INTEL_UNCORE_EVENT_DESC(data_writes.unit, "MiB"),
+
+       { /* end: all zeroes */ },
+};
+
+#define SNB_UNCORE_PCI_IMC_EVENT_MASK          0xff
+#define SNB_UNCORE_PCI_IMC_BAR_OFFSET          0x48
+
+/* page size multiple covering all config regs */
+#define SNB_UNCORE_PCI_IMC_MAP_SIZE            0x6000
+
+#define SNB_UNCORE_PCI_IMC_DATA_READS          0x1
+#define SNB_UNCORE_PCI_IMC_DATA_READS_BASE     0x5050
+#define SNB_UNCORE_PCI_IMC_DATA_WRITES         0x2
+#define SNB_UNCORE_PCI_IMC_DATA_WRITES_BASE    0x5054
+#define SNB_UNCORE_PCI_IMC_CTR_BASE            SNB_UNCORE_PCI_IMC_DATA_READS_BASE
+
+static struct attribute *snb_uncore_imc_formats_attr[] = {
+       &format_attr_event.attr,
+       NULL,
+};
+
+static struct attribute_group snb_uncore_imc_format_group = {
+       .name = "format",
+       .attrs = snb_uncore_imc_formats_attr,
+};
+
+static void snb_uncore_imc_init_box(struct intel_uncore_box *box)
+{
+       struct pci_dev *pdev = box->pci_dev;
+       u32 addr_lo, addr_hi;
+       resource_size_t addr;
+
+       pci_read_config_dword(pdev, SNB_UNCORE_PCI_IMC_BAR_OFFSET, &addr_lo);
+       addr = addr_lo;
+
+#ifdef CONFIG_PHYS_ADDR_T_64BIT
+       pci_read_config_dword(pdev, SNB_UNCORE_PCI_IMC_BAR_OFFSET+4, &addr_hi);
+       addr = ((resource_size_t)addr_hi << 32) | addr_lo;
+#endif
+
+       addr &= ~(PAGE_SIZE - 1);
+
+       box->io_addr = ioremap(addr, SNB_UNCORE_PCI_IMC_MAP_SIZE);
+       box->hrtimer_duration = UNCORE_SNB_IMC_HRTIMER_INTERVAL;
+}
+
+static void snb_uncore_imc_enable_box(struct intel_uncore_box *box)
+{}
+
+static void snb_uncore_imc_disable_box(struct intel_uncore_box *box)
+{}
+
+static void snb_uncore_imc_enable_event(struct intel_uncore_box *box, struct perf_event *event)
+{}
+
+static void snb_uncore_imc_disable_event(struct intel_uncore_box *box, struct perf_event *event)
+{}
+
+static u64 snb_uncore_imc_read_counter(struct intel_uncore_box *box, struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+
+       return (u64)*(unsigned int *)(box->io_addr + hwc->event_base);
+}
+
+/*
+ * custom event_init() function because we define our own fixed, free
+ * running counters, so we do not want to conflict with generic uncore
+ * logic. Also simplifies processing
+ */
+static int snb_uncore_imc_event_init(struct perf_event *event)
+{
+       struct intel_uncore_pmu *pmu;
+       struct intel_uncore_box *box;
+       struct hw_perf_event *hwc = &event->hw;
+       u64 cfg = event->attr.config & SNB_UNCORE_PCI_IMC_EVENT_MASK;
+       int idx, base;
+
+       if (event->attr.type != event->pmu->type)
+               return -ENOENT;
+
+       pmu = uncore_event_to_pmu(event);
+       /* no device found for this pmu */
+       if (pmu->func_id < 0)
+               return -ENOENT;
+
+       /* Sampling not supported yet */
+       if (hwc->sample_period)
+               return -EINVAL;
+
+       /* unsupported modes and filters */
+       if (event->attr.exclude_user   ||
+           event->attr.exclude_kernel ||
+           event->attr.exclude_hv     ||
+           event->attr.exclude_idle   ||
+           event->attr.exclude_host   ||
+           event->attr.exclude_guest  ||
+           event->attr.sample_period) /* no sampling */
+               return -EINVAL;
+
+       /*
+        * Place all uncore events for a particular physical package
+        * onto a single cpu
+        */
+       if (event->cpu < 0)
+               return -EINVAL;
+
+       /* check only supported bits are set */
+       if (event->attr.config & ~SNB_UNCORE_PCI_IMC_EVENT_MASK)
+               return -EINVAL;
+
+       box = uncore_pmu_to_box(pmu, event->cpu);
+       if (!box || box->cpu < 0)
+               return -EINVAL;
+
+       event->cpu = box->cpu;
+
+       event->hw.idx = -1;
+       event->hw.last_tag = ~0ULL;
+       event->hw.extra_reg.idx = EXTRA_REG_NONE;
+       event->hw.branch_reg.idx = EXTRA_REG_NONE;
+       /*
+        * check event is known (whitelist, determines counter)
+        */
+       switch (cfg) {
+       case SNB_UNCORE_PCI_IMC_DATA_READS:
+               base = SNB_UNCORE_PCI_IMC_DATA_READS_BASE;
+               idx = UNCORE_PMC_IDX_FIXED;
+               break;
+       case SNB_UNCORE_PCI_IMC_DATA_WRITES:
+               base = SNB_UNCORE_PCI_IMC_DATA_WRITES_BASE;
+               idx = UNCORE_PMC_IDX_FIXED + 1;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* must be done before validate_group */
+       event->hw.event_base = base;
+       event->hw.config = cfg;
+       event->hw.idx = idx;
+
+       /* no group validation needed, we have free running counters */
+
+       return 0;
+}
+
+static int snb_uncore_imc_hw_config(struct intel_uncore_box *box, struct perf_event *event)
+{
+       return 0;
+}
+
+static void snb_uncore_imc_event_start(struct perf_event *event, int flags)
+{
+       struct intel_uncore_box *box = uncore_event_to_box(event);
+       u64 count;
+
+       if (WARN_ON_ONCE(!(event->hw.state & PERF_HES_STOPPED)))
+               return;
+
+       event->hw.state = 0;
+       box->n_active++;
+
+       list_add_tail(&event->active_entry, &box->active_list);
+
+       count = snb_uncore_imc_read_counter(box, event);
+       local64_set(&event->hw.prev_count, count);
+
+       if (box->n_active == 1)
+               uncore_pmu_start_hrtimer(box);
+}
+
+static void snb_uncore_imc_event_stop(struct perf_event *event, int flags)
+{
+       struct intel_uncore_box *box = uncore_event_to_box(event);
+       struct hw_perf_event *hwc = &event->hw;
+
+       if (!(hwc->state & PERF_HES_STOPPED)) {
+               box->n_active--;
+
+               WARN_ON_ONCE(hwc->state & PERF_HES_STOPPED);
+               hwc->state |= PERF_HES_STOPPED;
+
+               list_del(&event->active_entry);
+
+               if (box->n_active == 0)
+                       uncore_pmu_cancel_hrtimer(box);
+       }
+
+       if ((flags & PERF_EF_UPDATE) && !(hwc->state & PERF_HES_UPTODATE)) {
+               /*
+                * Drain the remaining delta count out of a event
+                * that we are disabling:
+                */
+               uncore_perf_event_update(box, event);
+               hwc->state |= PERF_HES_UPTODATE;
+       }
+}
+
+static int snb_uncore_imc_event_add(struct perf_event *event, int flags)
+{
+       struct intel_uncore_box *box = uncore_event_to_box(event);
+       struct hw_perf_event *hwc = &event->hw;
+
+       if (!box)
+               return -ENODEV;
+
+       hwc->state = PERF_HES_UPTODATE | PERF_HES_STOPPED;
+       if (!(flags & PERF_EF_START))
+               hwc->state |= PERF_HES_ARCH;
+
+       snb_uncore_imc_event_start(event, 0);
+
+       box->n_events++;
+
+       return 0;
+}
+
+static void snb_uncore_imc_event_del(struct perf_event *event, int flags)
+{
+       struct intel_uncore_box *box = uncore_event_to_box(event);
+       int i;
+
+       snb_uncore_imc_event_stop(event, PERF_EF_UPDATE);
+
+       for (i = 0; i < box->n_events; i++) {
+               if (event == box->event_list[i]) {
+                       --box->n_events;
+                       break;
+               }
+       }
+}
+
+static int snb_pci2phy_map_init(int devid)
+{
+       struct pci_dev *dev = NULL;
+       int bus;
+
+       dev = pci_get_device(PCI_VENDOR_ID_INTEL, devid, dev);
+       if (!dev)
+               return -ENOTTY;
+
+       bus = dev->bus->number;
+
+       pcibus_to_physid[bus] = 0;
+
+       pci_dev_put(dev);
+
+       return 0;
+}
+
+static struct pmu snb_uncore_imc_pmu = {
+       .task_ctx_nr    = perf_invalid_context,
+       .event_init     = snb_uncore_imc_event_init,
+       .add            = snb_uncore_imc_event_add,
+       .del            = snb_uncore_imc_event_del,
+       .start          = snb_uncore_imc_event_start,
+       .stop           = snb_uncore_imc_event_stop,
+       .read           = uncore_pmu_event_read,
+};
+
+static struct intel_uncore_ops snb_uncore_imc_ops = {
+       .init_box       = snb_uncore_imc_init_box,
+       .enable_box     = snb_uncore_imc_enable_box,
+       .disable_box    = snb_uncore_imc_disable_box,
+       .disable_event  = snb_uncore_imc_disable_event,
+       .enable_event   = snb_uncore_imc_enable_event,
+       .hw_config      = snb_uncore_imc_hw_config,
+       .read_counter   = snb_uncore_imc_read_counter,
+};
+
+static struct intel_uncore_type snb_uncore_imc = {
+       .name           = "imc",
+       .num_counters   = 2,
+       .num_boxes      = 1,
+       .fixed_ctr_bits = 32,
+       .fixed_ctr      = SNB_UNCORE_PCI_IMC_CTR_BASE,
+       .event_descs    = snb_uncore_imc_events,
+       .format_group   = &snb_uncore_imc_format_group,
+       .perf_ctr       = SNB_UNCORE_PCI_IMC_DATA_READS_BASE,
+       .event_mask     = SNB_UNCORE_PCI_IMC_EVENT_MASK,
+       .ops            = &snb_uncore_imc_ops,
+       .pmu            = &snb_uncore_imc_pmu,
+};
+
+static struct intel_uncore_type *snb_pci_uncores[] = {
+       [SNB_PCI_UNCORE_IMC]    = &snb_uncore_imc,
+       NULL,
+};
+
+static DEFINE_PCI_DEVICE_TABLE(snb_uncore_pci_ids) = {
+       { /* IMC */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SNB_IMC),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
+       },
+};
+
+static DEFINE_PCI_DEVICE_TABLE(ivb_uncore_pci_ids) = {
+       { /* IMC */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IVB_IMC),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
+       },
+};
+
+static DEFINE_PCI_DEVICE_TABLE(hsw_uncore_pci_ids) = {
+       { /* IMC */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HSW_IMC),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
+       },
+};
+
+static struct pci_driver snb_uncore_pci_driver = {
+       .name           = "snb_uncore",
+       .id_table       = snb_uncore_pci_ids,
+};
+
+static struct pci_driver ivb_uncore_pci_driver = {
+       .name           = "ivb_uncore",
+       .id_table       = ivb_uncore_pci_ids,
+};
+
+static struct pci_driver hsw_uncore_pci_driver = {
+       .name           = "hsw_uncore",
+       .id_table       = hsw_uncore_pci_ids,
+};
+
 /* end of Sandy Bridge uncore support */
 
 /* Nehalem uncore support */
@@ -2789,6 +3169,7 @@ again:
 static enum hrtimer_restart uncore_pmu_hrtimer(struct hrtimer *hrtimer)
 {
        struct intel_uncore_box *box;
+       struct perf_event *event;
        unsigned long flags;
        int bit;
 
@@ -2801,19 +3182,27 @@ static enum hrtimer_restart uncore_pmu_hrtimer(struct hrtimer *hrtimer)
         */
        local_irq_save(flags);
 
+       /*
+        * handle boxes with an active event list as opposed to active
+        * counters
+        */
+       list_for_each_entry(event, &box->active_list, active_entry) {
+               uncore_perf_event_update(box, event);
+       }
+
        for_each_set_bit(bit, box->active_mask, UNCORE_PMC_IDX_MAX)
                uncore_perf_event_update(box, box->events[bit]);
 
        local_irq_restore(flags);
 
-       hrtimer_forward_now(hrtimer, ns_to_ktime(UNCORE_PMU_HRTIMER_INTERVAL));
+       hrtimer_forward_now(hrtimer, ns_to_ktime(box->hrtimer_duration));
        return HRTIMER_RESTART;
 }
 
 static void uncore_pmu_start_hrtimer(struct intel_uncore_box *box)
 {
        __hrtimer_start_range_ns(&box->hrtimer,
-                       ns_to_ktime(UNCORE_PMU_HRTIMER_INTERVAL), 0,
+                       ns_to_ktime(box->hrtimer_duration), 0,
                        HRTIMER_MODE_REL_PINNED, 0);
 }
 
@@ -2847,43 +3236,12 @@ static struct intel_uncore_box *uncore_alloc_box(struct intel_uncore_type *type,
        box->cpu = -1;
        box->phys_id = -1;
 
-       return box;
-}
+       /* set default hrtimer timeout */
+       box->hrtimer_duration = UNCORE_PMU_HRTIMER_INTERVAL;
 
-static struct intel_uncore_box *
-uncore_pmu_to_box(struct intel_uncore_pmu *pmu, int cpu)
-{
-       struct intel_uncore_box *box;
+       INIT_LIST_HEAD(&box->active_list);
 
-       box = *per_cpu_ptr(pmu->box, cpu);
-       if (box)
-               return box;
-
-       raw_spin_lock(&uncore_box_lock);
-       list_for_each_entry(box, &pmu->box_list, list) {
-               if (box->phys_id == topology_physical_package_id(cpu)) {
-                       atomic_inc(&box->refcnt);
-                       *per_cpu_ptr(pmu->box, cpu) = box;
-                       break;
-               }
-       }
-       raw_spin_unlock(&uncore_box_lock);
-
-       return *per_cpu_ptr(pmu->box, cpu);
-}
-
-static struct intel_uncore_pmu *uncore_event_to_pmu(struct perf_event *event)
-{
-       return container_of(event->pmu, struct intel_uncore_pmu, pmu);
-}
-
-static struct intel_uncore_box *uncore_event_to_box(struct perf_event *event)
-{
-       /*
-        * perf core schedules event on the basis of cpu, uncore events are
-        * collected by one of the cpus inside a physical package.
-        */
-       return uncore_pmu_to_box(uncore_event_to_pmu(event), smp_processor_id());
+       return box;
 }
 
 static int
@@ -3279,16 +3637,21 @@ static int __init uncore_pmu_register(struct intel_uncore_pmu *pmu)
 {
        int ret;
 
-       pmu->pmu = (struct pmu) {
-               .attr_groups    = pmu->type->attr_groups,
-               .task_ctx_nr    = perf_invalid_context,
-               .event_init     = uncore_pmu_event_init,
-               .add            = uncore_pmu_event_add,
-               .del            = uncore_pmu_event_del,
-               .start          = uncore_pmu_event_start,
-               .stop           = uncore_pmu_event_stop,
-               .read           = uncore_pmu_event_read,
-       };
+       if (!pmu->type->pmu) {
+               pmu->pmu = (struct pmu) {
+                       .attr_groups    = pmu->type->attr_groups,
+                       .task_ctx_nr    = perf_invalid_context,
+                       .event_init     = uncore_pmu_event_init,
+                       .add            = uncore_pmu_event_add,
+                       .del            = uncore_pmu_event_del,
+                       .start          = uncore_pmu_event_start,
+                       .stop           = uncore_pmu_event_stop,
+                       .read           = uncore_pmu_event_read,
+               };
+       } else {
+               pmu->pmu = *pmu->type->pmu;
+               pmu->pmu.attr_groups = pmu->type->attr_groups;
+       }
 
        if (pmu->type->num_boxes == 1) {
                if (strlen(pmu->type->name) > 0)
@@ -3501,6 +3864,28 @@ static int __init uncore_pci_init(void)
                pci_uncores = ivt_pci_uncores;
                uncore_pci_driver = &ivt_uncore_pci_driver;
                break;
+       case 42: /* Sandy Bridge */
+               ret = snb_pci2phy_map_init(PCI_DEVICE_ID_INTEL_SNB_IMC);
+               if (ret)
+                       return ret;
+               pci_uncores = snb_pci_uncores;
+               uncore_pci_driver = &snb_uncore_pci_driver;
+               break;
+       case 58: /* Ivy Bridge */
+               ret = snb_pci2phy_map_init(PCI_DEVICE_ID_INTEL_IVB_IMC);
+               if (ret)
+                       return ret;
+               pci_uncores = snb_pci_uncores;
+               uncore_pci_driver = &ivb_uncore_pci_driver;
+               break;
+       case 60: /* Haswell */
+       case 69: /* Haswell Celeron */
+               ret = snb_pci2phy_map_init(PCI_DEVICE_ID_INTEL_HSW_IMC);
+               if (ret)
+                       return ret;
+               pci_uncores = snb_pci_uncores;
+               uncore_pci_driver = &hsw_uncore_pci_driver;
+               break;
        default:
                return 0;
        }
@@ -3772,7 +4157,7 @@ static void __init uncore_cpu_setup(void *dummy)
 
 static int __init uncore_cpu_init(void)
 {
-       int ret, cpu, max_cores;
+       int ret, max_cores;
 
        max_cores = boot_cpu_data.x86_max_cores;
        switch (boot_cpu_data.x86_model) {
@@ -3816,29 +4201,6 @@ static int __init uncore_cpu_init(void)
        if (ret)
                return ret;
 
-       get_online_cpus();
-
-       for_each_online_cpu(cpu) {
-               int i, phys_id = topology_physical_package_id(cpu);
-
-               for_each_cpu(i, &uncore_cpu_mask) {
-                       if (phys_id == topology_physical_package_id(i)) {
-                               phys_id = -1;
-                               break;
-                       }
-               }
-               if (phys_id < 0)
-                       continue;
-
-               uncore_cpu_prepare(cpu, phys_id);
-               uncore_event_init_cpu(cpu);
-       }
-       on_each_cpu(uncore_cpu_setup, NULL, 1);
-
-       register_cpu_notifier(&uncore_cpu_nb);
-
-       put_online_cpus();
-
        return 0;
 }
 
@@ -3867,6 +4229,41 @@ static int __init uncore_pmus_register(void)
        return 0;
 }
 
+static void uncore_cpumask_init(void)
+{
+       int cpu;
+
+       /*
+        * ony invoke once from msr or pci init code
+        */
+       if (!cpumask_empty(&uncore_cpu_mask))
+               return;
+
+       get_online_cpus();
+
+       for_each_online_cpu(cpu) {
+               int i, phys_id = topology_physical_package_id(cpu);
+
+               for_each_cpu(i, &uncore_cpu_mask) {
+                       if (phys_id == topology_physical_package_id(i)) {
+                               phys_id = -1;
+                               break;
+                       }
+               }
+               if (phys_id < 0)
+                       continue;
+
+               uncore_cpu_prepare(cpu, phys_id);
+               uncore_event_init_cpu(cpu);
+       }
+       on_each_cpu(uncore_cpu_setup, NULL, 1);
+
+       register_cpu_notifier(&uncore_cpu_nb);
+
+       put_online_cpus();
+}
+
+
 static int __init intel_uncore_init(void)
 {
        int ret;
@@ -3885,6 +4282,7 @@ static int __init intel_uncore_init(void)
                uncore_pci_exit();
                goto fail;
        }
+       uncore_cpumask_init();
 
        uncore_pmus_register();
        return 0;
index a80ab71..90236f0 100644 (file)
@@ -6,6 +6,7 @@
 
 #define UNCORE_PMU_NAME_LEN            32
 #define UNCORE_PMU_HRTIMER_INTERVAL    (60LL * NSEC_PER_SEC)
+#define UNCORE_SNB_IMC_HRTIMER_INTERVAL (5ULL * NSEC_PER_SEC)
 
 #define UNCORE_FIXED_EVENT             0xff
 #define UNCORE_PMC_IDX_MAX_GENERIC     8
@@ -440,6 +441,7 @@ struct intel_uncore_type {
        struct intel_uncore_ops *ops;
        struct uncore_event_desc *event_descs;
        const struct attribute_group *attr_groups[4];
+       struct pmu *pmu; /* for custom pmu ops */
 };
 
 #define pmu_group attr_groups[0]
@@ -488,8 +490,11 @@ struct intel_uncore_box {
        u64 tags[UNCORE_PMC_IDX_MAX];
        struct pci_dev *pci_dev;
        struct intel_uncore_pmu *pmu;
+       u64 hrtimer_duration; /* hrtimer timeout for this box */
        struct hrtimer hrtimer;
        struct list_head list;
+       struct list_head active_list;
+       void *io_addr;
        struct intel_uncore_extra_reg shared_regs[0];
 };
 
index 3486e66..5d466b7 100644 (file)
@@ -1257,7 +1257,24 @@ again:
                        pass++;
                        goto again;
                }
-
+               /*
+                * Perf does test runs to see if a whole group can be assigned
+                * together succesfully.  There can be multiple rounds of this.
+                * Unfortunately, p4_pmu_swap_config_ts touches the hwc->config
+                * bits, such that the next round of group assignments will
+                * cause the above p4_should_swap_ts to pass instead of fail.
+                * This leads to counters exclusive to thread0 being used by
+                * thread1.
+                *
+                * Solve this with a cheap hack, reset the idx back to -1 to
+                * force a new lookup (p4_next_cntr) to get the right counter
+                * for the right thread.
+                *
+                * This probably doesn't comply with the general spirit of how
+                * perf wants to work, but P4 is special. :-(
+                */
+               if (p4_should_swap_ts(hwc->config, cpu))
+                       hwc->idx = -1;
                p4_pmu_swap_config_ts(hwc, cpu);
                if (assign)
                        assign[i] = cntr_idx;
@@ -1322,6 +1339,7 @@ static __initconst const struct x86_pmu p4_pmu = {
 __init int p4_pmu_init(void)
 {
        unsigned int low, high;
+       int i, reg;
 
        /* If we get stripped -- indexing fails */
        BUILD_BUG_ON(ARCH_P4_MAX_CCCR > INTEL_PMC_MAX_GENERIC);
@@ -1340,5 +1358,19 @@ __init int p4_pmu_init(void)
 
        x86_pmu = p4_pmu;
 
+       /*
+        * Even though the counters are configured to interrupt a particular
+        * logical processor when an overflow happens, testing has shown that
+        * on kdump kernels (which uses a single cpu), thread1's counter
+        * continues to run and will report an NMI on thread0.  Due to the
+        * overflow bug, this leads to a stream of unknown NMIs.
+        *
+        * Solve this by zero'ing out the registers to mimic a reset.
+        */
+       for (i = 0; i < x86_pmu.num_counters; i++) {
+               reg = x86_pmu_config_addr(i);
+               wrmsrl_safe(reg, 0ULL);
+       }
+
        return 0;
 }
index 6fcb49c..b4872b9 100644 (file)
@@ -87,6 +87,7 @@ __setup("unknown_nmi_panic", setup_unknown_nmi_panic);
 #define nmi_to_desc(type) (&nmi_desc[type])
 
 static u64 nmi_longest_ns = 1 * NSEC_PER_MSEC;
+
 static int __init nmi_warning_debugfs(void)
 {
        debugfs_create_u64("nmi_longest_ns", 0644,
@@ -95,6 +96,20 @@ static int __init nmi_warning_debugfs(void)
 }
 fs_initcall(nmi_warning_debugfs);
 
+static void nmi_max_handler(struct irq_work *w)
+{
+       struct nmiaction *a = container_of(w, struct nmiaction, irq_work);
+       int remainder_ns, decimal_msecs;
+       u64 whole_msecs = ACCESS_ONCE(a->max_duration);
+
+       remainder_ns = do_div(whole_msecs, (1000 * 1000));
+       decimal_msecs = remainder_ns / 1000;
+
+       printk_ratelimited(KERN_INFO
+               "INFO: NMI handler (%ps) took too long to run: %lld.%03d msecs\n",
+               a->handler, whole_msecs, decimal_msecs);
+}
+
 static int __kprobes nmi_handle(unsigned int type, struct pt_regs *regs, bool b2b)
 {
        struct nmi_desc *desc = nmi_to_desc(type);
@@ -110,26 +125,20 @@ static int __kprobes nmi_handle(unsigned int type, struct pt_regs *regs, bool b2
         * to handle those situations.
         */
        list_for_each_entry_rcu(a, &desc->head, list) {
-               u64 before, delta, whole_msecs;
-               int remainder_ns, decimal_msecs, thishandled;
+               int thishandled;
+               u64 delta;
 
-               before = sched_clock();
+               delta = sched_clock();
                thishandled = a->handler(type, regs);
                handled += thishandled;
-               delta = sched_clock() - before;
+               delta = sched_clock() - delta;
                trace_nmi_handler(a->handler, (int)delta, thishandled);
 
-               if (delta < nmi_longest_ns)
+               if (delta < nmi_longest_ns || delta < a->max_duration)
                        continue;
 
-               nmi_longest_ns = delta;
-               whole_msecs = delta;
-               remainder_ns = do_div(whole_msecs, (1000 * 1000));
-               decimal_msecs = remainder_ns / 1000;
-               printk_ratelimited(KERN_INFO
-                       "INFO: NMI handler (%ps) took too long to run: "
-                       "%lld.%03d msecs\n", a->handler, whole_msecs,
-                       decimal_msecs);
+               a->max_duration = delta;
+               irq_work_queue(&a->irq_work);
        }
 
        rcu_read_unlock();
@@ -146,6 +155,8 @@ int __register_nmi_handler(unsigned int type, struct nmiaction *action)
        if (!action->handler)
                return -EINVAL;
 
+       init_irq_work(&action->irq_work, nmi_max_handler);
+
        spin_lock_irqsave(&desc->lock, flags);
 
        /*
index 6601702..19ae05d 100644 (file)
@@ -30,7 +30,9 @@ void init_irq_work(struct irq_work *work, void (*func)(struct irq_work *))
        work->func = func;
 }
 
-void irq_work_queue(struct irq_work *work);
+#define DEFINE_IRQ_WORK(name, _f) struct irq_work name = { .func = (_f), }
+
+bool irq_work_queue(struct irq_work *work);
 void irq_work_run(void);
 void irq_work_sync(struct irq_work *work);
 
index 97fbecd..7399e6a 100644 (file)
 
 #define PCI_VENDOR_ID_INTEL            0x8086
 #define PCI_DEVICE_ID_INTEL_EESSC      0x0008
+#define PCI_DEVICE_ID_INTEL_SNB_IMC    0x0100
+#define PCI_DEVICE_ID_INTEL_IVB_IMC    0x0154
+#define PCI_DEVICE_ID_INTEL_HSW_IMC    0x0c00
 #define PCI_DEVICE_ID_INTEL_PXHD_0     0x0320
 #define PCI_DEVICE_ID_INTEL_PXHD_1     0x0321
 #define PCI_DEVICE_ID_INTEL_PXH_0      0x0329
index fa0b2d4..fa99006 100644 (file)
@@ -231,11 +231,29 @@ int perf_cpu_time_max_percent_handler(struct ctl_table *table, int write,
 #define NR_ACCUMULATED_SAMPLES 128
 static DEFINE_PER_CPU(u64, running_sample_length);
 
-void perf_sample_event_took(u64 sample_len_ns)
+static void perf_duration_warn(struct irq_work *w)
 {
+       u64 allowed_ns = ACCESS_ONCE(perf_sample_allowed_ns);
        u64 avg_local_sample_len;
        u64 local_samples_len;
+
+       local_samples_len = __get_cpu_var(running_sample_length);
+       avg_local_sample_len = local_samples_len/NR_ACCUMULATED_SAMPLES;
+
+       printk_ratelimited(KERN_WARNING
+                       "perf interrupt took too long (%lld > %lld), lowering "
+                       "kernel.perf_event_max_sample_rate to %d\n",
+                       avg_local_sample_len, allowed_ns >> 1,
+                       sysctl_perf_event_sample_rate);
+}
+
+static DEFINE_IRQ_WORK(perf_duration_work, perf_duration_warn);
+
+void perf_sample_event_took(u64 sample_len_ns)
+{
        u64 allowed_ns = ACCESS_ONCE(perf_sample_allowed_ns);
+       u64 avg_local_sample_len;
+       u64 local_samples_len;
 
        if (allowed_ns == 0)
                return;
@@ -263,13 +281,14 @@ void perf_sample_event_took(u64 sample_len_ns)
        sysctl_perf_event_sample_rate = max_samples_per_tick * HZ;
        perf_sample_period_ns = NSEC_PER_SEC / sysctl_perf_event_sample_rate;
 
-       printk_ratelimited(KERN_WARNING
-                       "perf samples too long (%lld > %lld), lowering "
-                       "kernel.perf_event_max_sample_rate to %d\n",
-                       avg_local_sample_len, allowed_ns,
-                       sysctl_perf_event_sample_rate);
-
        update_perf_cpu_limits();
+
+       if (!irq_work_queue(&perf_duration_work)) {
+               early_printk("perf interrupt took too long (%lld > %lld), lowering "
+                            "kernel.perf_event_max_sample_rate to %d\n",
+                            avg_local_sample_len, allowed_ns >> 1,
+                            sysctl_perf_event_sample_rate);
+       }
 }
 
 static atomic64_t perf_event_id;
index 55fcce6..a82170e 100644 (file)
@@ -61,11 +61,11 @@ void __weak arch_irq_work_raise(void)
  *
  * Can be re-enqueued while the callback is still in progress.
  */
-void irq_work_queue(struct irq_work *work)
+bool irq_work_queue(struct irq_work *work)
 {
        /* Only queue if not already pending */
        if (!irq_work_claim(work))
-               return;
+               return false;
 
        /* Queue the entry and raise the IPI if needed. */
        preempt_disable();
@@ -83,6 +83,8 @@ void irq_work_queue(struct irq_work *work)
        }
 
        preempt_enable();
+
+       return true;
 }
 EXPORT_SYMBOL_GPL(irq_work_queue);
 
diff --git a/tools/include/linux/hash.h b/tools/include/linux/hash.h
new file mode 100644 (file)
index 0000000..d026c65
--- /dev/null
@@ -0,0 +1,5 @@
+#include "../../../include/linux/hash.h"
+
+#ifndef _TOOLS_LINUX_HASH_H
+#define _TOOLS_LINUX_HASH_H
+#endif
index ed2f51e..ce00f7e 100644 (file)
@@ -9,8 +9,10 @@ LIB_H=
 LIB_OBJS=
 
 LIB_H += fs/debugfs.h
+LIB_H += fs/fs.h
 
 LIB_OBJS += $(OUTPUT)fs/debugfs.o
+LIB_OBJS += $(OUTPUT)fs/fs.o
 
 LIBFILE = libapikfs.a
 
similarity index 91%
rename from tools/perf/util/fs.c
rename to tools/lib/api/fs/fs.c
index f5be1f2..5b5eb78 100644 (file)
@@ -1,8 +1,13 @@
+/* TODO merge/factor in debugfs.c here */
 
-/* TODO merge/factor into tools/lib/lk/debugfs.c */
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/vfs.h>
 
-#include "util.h"
-#include "util/fs.h"
+#include "debugfs.h"
+#include "fs.h"
 
 static const char * const sysfs__fs_known_mountpoints[] = {
        "/sys",
similarity index 50%
rename from tools/perf/util/include/linux/magic.h
rename to tools/lib/api/fs/fs.h
index 07d63cf..cb70495 100644 (file)
@@ -1,9 +1,5 @@
-#ifndef _PERF_LINUX_MAGIC_H_
-#define _PERF_LINUX_MAGIC_H_
-
-#ifndef DEBUGFS_MAGIC
-#define DEBUGFS_MAGIC          0x64626720
-#endif
+#ifndef __API_FS__
+#define __API_FS__
 
 #ifndef SYSFS_MAGIC
 #define SYSFS_MAGIC            0x62656572
@@ -13,4 +9,6 @@
 #define PROC_SUPER_MAGIC       0x9fa0
 #endif
 
-#endif
+const char *sysfs__mountpoint(void);
+const char *procfs__mountpoint(void);
+#endif /* __API_FS__ */
index f41572d..c0c87c8 100644 (file)
@@ -6,6 +6,7 @@ tools/lib/symbol/kallsyms.c
 tools/lib/symbol/kallsyms.h
 tools/include/asm/bug.h
 tools/include/linux/compiler.h
+tools/include/linux/hash.h
 include/linux/const.h
 include/linux/perf_event.h
 include/linux/rbtree.h
index 7257e7e..77b153f 100644 (file)
@@ -208,7 +208,7 @@ LIB_H += ../../include/uapi/linux/perf_event.h
 LIB_H += ../../include/linux/rbtree.h
 LIB_H += ../../include/linux/list.h
 LIB_H += ../../include/uapi/linux/const.h
-LIB_H += ../../include/linux/hash.h
+LIB_H += ../include/linux/hash.h
 LIB_H += ../../include/linux/stringify.h
 LIB_H += util/include/linux/bitmap.h
 LIB_H += util/include/linux/bitops.h
@@ -218,9 +218,7 @@ LIB_H += util/include/linux/ctype.h
 LIB_H += util/include/linux/kernel.h
 LIB_H += util/include/linux/list.h
 LIB_H += util/include/linux/export.h
-LIB_H += util/include/linux/magic.h
 LIB_H += util/include/linux/poison.h
-LIB_H += util/include/linux/prefetch.h
 LIB_H += util/include/linux/rbtree.h
 LIB_H += util/include/linux/rbtree_augmented.h
 LIB_H += util/include/linux/string.h
@@ -244,7 +242,6 @@ LIB_H += util/cache.h
 LIB_H += util/callchain.h
 LIB_H += util/build-id.h
 LIB_H += util/debug.h
-LIB_H += util/fs.h
 LIB_H += util/pmu.h
 LIB_H += util/event.h
 LIB_H += util/evsel.h
@@ -306,7 +303,6 @@ LIB_OBJS += $(OUTPUT)util/annotate.o
 LIB_OBJS += $(OUTPUT)util/build-id.o
 LIB_OBJS += $(OUTPUT)util/config.o
 LIB_OBJS += $(OUTPUT)util/ctype.o
-LIB_OBJS += $(OUTPUT)util/fs.o
 LIB_OBJS += $(OUTPUT)util/pmu.o
 LIB_OBJS += $(OUTPUT)util/environment.o
 LIB_OBJS += $(OUTPUT)util/event.o
@@ -408,6 +404,11 @@ endif
 LIB_OBJS += $(OUTPUT)tests/code-reading.o
 LIB_OBJS += $(OUTPUT)tests/sample-parsing.o
 LIB_OBJS += $(OUTPUT)tests/parse-no-sample-id-all.o
+ifndef NO_LIBUNWIND
+ifeq ($(ARCH),x86)
+LIB_OBJS += $(OUTPUT)tests/dwarf-unwind.o
+endif
+endif
 
 BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o
 BUILTIN_OBJS += $(OUTPUT)builtin-bench.o
@@ -476,7 +477,7 @@ endif # NO_DWARF
 endif # NO_LIBELF
 
 ifndef NO_LIBUNWIND
-  LIB_OBJS += $(OUTPUT)util/unwind.o
+  LIB_OBJS += $(OUTPUT)util/unwind-libunwind.o
 endif
 LIB_OBJS += $(OUTPUT)tests/keep-tracking.o
 
@@ -533,6 +534,7 @@ ifeq ($(NO_PERF_REGS),0)
   ifeq ($(ARCH),x86)
     LIB_H += arch/x86/include/perf_regs.h
   endif
+  LIB_OBJS += $(OUTPUT)util/perf_regs.o
 endif
 
 ifndef NO_LIBNUMA
@@ -655,6 +657,9 @@ $(OUTPUT)tests/python-use.o: tests/python-use.c $(OUTPUT)PERF-CFLAGS
                -DPYTHON='"$(PYTHON_WORD)"' \
                $<
 
+$(OUTPUT)tests/dwarf-unwind.o: tests/dwarf-unwind.c
+       $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -fno-optimize-sibling-calls $<
+
 $(OUTPUT)util/config.o: util/config.c $(OUTPUT)PERF-CFLAGS
        $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
 
index fe9b61e..67e9b3d 100644 (file)
@@ -3,5 +3,5 @@ PERF_HAVE_DWARF_REGS := 1
 LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o
 endif
 ifndef NO_LIBUNWIND
-LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind.o
+LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind-libunwind.o
 endif
similarity index 95%
rename from tools/perf/arch/arm/util/unwind.c
rename to tools/perf/arch/arm/util/unwind-libunwind.c
index da3dc95..729ed69 100644 (file)
@@ -4,7 +4,7 @@
 #include "perf_regs.h"
 #include "../../util/unwind.h"
 
-int unwind__arch_reg_id(int regnum)
+int libunwind__arch_reg_id(int regnum)
 {
        switch (regnum) {
        case UNW_ARM_R0:
index 8801fe0..4fa9be9 100644 (file)
@@ -3,7 +3,9 @@ PERF_HAVE_DWARF_REGS := 1
 LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o
 endif
 ifndef NO_LIBUNWIND
-LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind.o
+LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind-libunwind.o
+LIB_OBJS += $(OUTPUT)arch/$(ARCH)/tests/regs_load.o
+LIB_OBJS += $(OUTPUT)arch/$(ARCH)/tests/dwarf-unwind.o
 endif
 LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o
 LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/tsc.o
index e84ca76..fc819ca 100644 (file)
@@ -5,14 +5,20 @@
 #include "../../util/types.h"
 #include <asm/perf_regs.h>
 
+void perf_regs_load(u64 *regs);
+
 #ifndef HAVE_ARCH_X86_64_SUPPORT
 #define PERF_REGS_MASK ((1ULL << PERF_REG_X86_32_MAX) - 1)
+#define PERF_REGS_MAX PERF_REG_X86_32_MAX
+#define PERF_SAMPLE_REGS_ABI PERF_SAMPLE_REGS_ABI_32
 #else
 #define REG_NOSUPPORT ((1ULL << PERF_REG_X86_DS) | \
                       (1ULL << PERF_REG_X86_ES) | \
                       (1ULL << PERF_REG_X86_FS) | \
                       (1ULL << PERF_REG_X86_GS))
 #define PERF_REGS_MASK (((1ULL << PERF_REG_X86_64_MAX) - 1) & ~REG_NOSUPPORT)
+#define PERF_REGS_MAX PERF_REG_X86_64_MAX
+#define PERF_SAMPLE_REGS_ABI PERF_SAMPLE_REGS_ABI_64
 #endif
 #define PERF_REG_IP PERF_REG_X86_IP
 #define PERF_REG_SP PERF_REG_X86_SP
diff --git a/tools/perf/arch/x86/tests/dwarf-unwind.c b/tools/perf/arch/x86/tests/dwarf-unwind.c
new file mode 100644 (file)
index 0000000..b602ad9
--- /dev/null
@@ -0,0 +1,59 @@
+#include <string.h>
+#include "perf_regs.h"
+#include "thread.h"
+#include "map.h"
+#include "event.h"
+#include "tests/tests.h"
+
+#define STACK_SIZE 8192
+
+static int sample_ustack(struct perf_sample *sample,
+                        struct thread *thread, u64 *regs)
+{
+       struct stack_dump *stack = &sample->user_stack;
+       struct map *map;
+       unsigned long sp;
+       u64 stack_size, *buf;
+
+       buf = malloc(STACK_SIZE);
+       if (!buf) {
+               pr_debug("failed to allocate sample uregs data\n");
+               return -1;
+       }
+
+       sp = (unsigned long) regs[PERF_REG_X86_SP];
+
+       map = map_groups__find(&thread->mg, MAP__FUNCTION, (u64) sp);
+       if (!map) {
+               pr_debug("failed to get stack map\n");
+               return -1;
+       }
+
+       stack_size = map->end - sp;
+       stack_size = stack_size > STACK_SIZE ? STACK_SIZE : stack_size;
+
+       memcpy(buf, (void *) sp, stack_size);
+       stack->data = (char *) buf;
+       stack->size = stack_size;
+       return 0;
+}
+
+int test__arch_unwind_sample(struct perf_sample *sample,
+                            struct thread *thread)
+{
+       struct regs_dump *regs = &sample->user_regs;
+       u64 *buf;
+
+       buf = malloc(sizeof(u64) * PERF_REGS_MAX);
+       if (!buf) {
+               pr_debug("failed to allocate sample uregs data\n");
+               return -1;
+       }
+
+       perf_regs_load(buf);
+       regs->abi  = PERF_SAMPLE_REGS_ABI;
+       regs->regs = buf;
+       regs->mask = PERF_REGS_MASK;
+
+       return sample_ustack(sample, thread, buf);
+}
diff --git a/tools/perf/arch/x86/tests/regs_load.S b/tools/perf/arch/x86/tests/regs_load.S
new file mode 100644 (file)
index 0000000..99167bf
--- /dev/null
@@ -0,0 +1,92 @@
+
+#include <linux/linkage.h>
+
+#define AX      0
+#define BX      1 * 8
+#define CX      2 * 8
+#define DX      3 * 8
+#define SI      4 * 8
+#define DI      5 * 8
+#define BP      6 * 8
+#define SP      7 * 8
+#define IP      8 * 8
+#define FLAGS   9 * 8
+#define CS     10 * 8
+#define SS     11 * 8
+#define DS     12 * 8
+#define ES     13 * 8
+#define FS     14 * 8
+#define GS     15 * 8
+#define R8     16 * 8
+#define R9     17 * 8
+#define R10    18 * 8
+#define R11    19 * 8
+#define R12    20 * 8
+#define R13    21 * 8
+#define R14    22 * 8
+#define R15    23 * 8
+
+.text
+#ifdef HAVE_ARCH_X86_64_SUPPORT
+ENTRY(perf_regs_load)
+       movq %rax, AX(%rdi)
+       movq %rbx, BX(%rdi)
+       movq %rcx, CX(%rdi)
+       movq %rdx, DX(%rdi)
+       movq %rsi, SI(%rdi)
+       movq %rdi, DI(%rdi)
+       movq %rbp, BP(%rdi)
+
+       leaq 8(%rsp), %rax /* exclude this call.  */
+       movq %rax, SP(%rdi)
+
+       movq 0(%rsp), %rax
+       movq %rax, IP(%rdi)
+
+       movq $0, FLAGS(%rdi)
+       movq $0, CS(%rdi)
+       movq $0, SS(%rdi)
+       movq $0, DS(%rdi)
+       movq $0, ES(%rdi)
+       movq $0, FS(%rdi)
+       movq $0, GS(%rdi)
+
+       movq %r8,  R8(%rdi)
+       movq %r9,  R9(%rdi)
+       movq %r10, R10(%rdi)
+       movq %r11, R11(%rdi)
+       movq %r12, R12(%rdi)
+       movq %r13, R13(%rdi)
+       movq %r14, R14(%rdi)
+       movq %r15, R15(%rdi)
+       ret
+ENDPROC(perf_regs_load)
+#else
+ENTRY(perf_regs_load)
+       push %edi
+       movl 8(%esp), %edi
+       movl %eax, AX(%edi)
+       movl %ebx, BX(%edi)
+       movl %ecx, CX(%edi)
+       movl %edx, DX(%edi)
+       movl %esi, SI(%edi)
+       pop %eax
+       movl %eax, DI(%edi)
+       movl %ebp, BP(%edi)
+
+       leal 4(%esp), %eax /* exclude this call.  */
+       movl %eax, SP(%edi)
+
+       movl 0(%esp), %eax
+       movl %eax, IP(%edi)
+
+       movl $0, FLAGS(%edi)
+       movl $0, CS(%edi)
+       movl $0, SS(%edi)
+       movl $0, DS(%edi)
+       movl $0, ES(%edi)
+       movl $0, FS(%edi)
+       movl $0, GS(%edi)
+       ret
+ENDPROC(perf_regs_load)
+#endif
similarity index 95%
rename from tools/perf/arch/x86/util/unwind.c
rename to tools/perf/arch/x86/util/unwind-libunwind.c
index 456a88c..3261f68 100644 (file)
@@ -5,7 +5,7 @@
 #include "../../util/unwind.h"
 
 #ifdef HAVE_ARCH_X86_64_SUPPORT
-int unwind__arch_reg_id(int regnum)
+int libunwind__arch_reg_id(int regnum)
 {
        int id;
 
@@ -69,7 +69,7 @@ int unwind__arch_reg_id(int regnum)
        return id;
 }
 #else
-int unwind__arch_reg_id(int regnum)
+int libunwind__arch_reg_id(int regnum)
 {
        int id;
 
index b346601..3a73875 100644 (file)
@@ -312,7 +312,6 @@ found:
        sample_sw.period = sample->period;
        sample_sw.time   = sample->time;
        perf_event__synthesize_sample(event_sw, evsel->attr.sample_type,
-                                     evsel->attr.sample_regs_user,
                                      evsel->attr.read_format, &sample_sw,
                                      false);
        build_id__mark_dso_hit(tool, event_sw, &sample_sw, evsel, machine);
index 7894888..cdcd4eb 100644 (file)
@@ -268,9 +268,9 @@ static int opt_set_filter(const struct option *opt __maybe_unused,
        return 0;
 }
 
-static void init_params(void)
+static int init_params(void)
 {
-       line_range__init(&params.line_range);
+       return line_range__init(&params.line_range);
 }
 
 static void cleanup_params(void)
@@ -515,9 +515,11 @@ int cmd_probe(int argc, const char **argv, const char *prefix)
 {
        int ret;
 
-       init_params();
-       ret = __cmd_probe(argc, argv, prefix);
-       cleanup_params();
+       ret = init_params();
+       if (!ret) {
+               ret = __cmd_probe(argc, argv, prefix);
+               cleanup_params();
+       }
 
        return ret;
 }
index af47531..eb524f9 100644 (file)
@@ -649,7 +649,7 @@ error:
        return ret;
 }
 
-#ifdef HAVE_LIBUNWIND_SUPPORT
+#ifdef HAVE_DWARF_UNWIND_SUPPORT
 static int get_stack_size(char *str, unsigned long *_size)
 {
        char *endptr;
@@ -675,7 +675,7 @@ static int get_stack_size(char *str, unsigned long *_size)
               max_size, str);
        return -1;
 }
-#endif /* HAVE_LIBUNWIND_SUPPORT */
+#endif /* HAVE_DWARF_UNWIND_SUPPORT */
 
 int record_parse_callchain(const char *arg, struct record_opts *opts)
 {
@@ -704,7 +704,7 @@ int record_parse_callchain(const char *arg, struct record_opts *opts)
                                       "needed for -g fp\n");
                        break;
 
-#ifdef HAVE_LIBUNWIND_SUPPORT
+#ifdef HAVE_DWARF_UNWIND_SUPPORT
                /* Dwarf style */
                } else if (!strncmp(name, "dwarf", sizeof("dwarf"))) {
                        const unsigned long default_stack_dump_size = 8192;
@@ -720,7 +720,7 @@ int record_parse_callchain(const char *arg, struct record_opts *opts)
                                ret = get_stack_size(tok, &size);
                                opts->stack_dump_size = size;
                        }
-#endif /* HAVE_LIBUNWIND_SUPPORT */
+#endif /* HAVE_DWARF_UNWIND_SUPPORT */
                } else {
                        pr_err("callchain: Unknown --call-graph option "
                               "value: %s\n", arg);
@@ -735,7 +735,9 @@ int record_parse_callchain(const char *arg, struct record_opts *opts)
 
 static void callchain_debug(struct record_opts *opts)
 {
-       pr_debug("callchain: type %d\n", opts->call_graph);
+       static const char *str[CALLCHAIN_MAX] = { "NONE", "FP", "DWARF" };
+
+       pr_debug("callchain: type %s\n", str[opts->call_graph]);
 
        if (opts->call_graph == CALLCHAIN_DWARF)
                pr_debug("callchain: stack dump size %d\n",
@@ -749,6 +751,8 @@ int record_parse_callchain_opt(const struct option *opt,
        struct record_opts *opts = opt->value;
        int ret;
 
+       opts->call_graph_enabled = !unset;
+
        /* --no-call-graph */
        if (unset) {
                opts->call_graph = CALLCHAIN_NONE;
@@ -769,6 +773,8 @@ int record_callchain_opt(const struct option *opt,
 {
        struct record_opts *opts = opt->value;
 
+       opts->call_graph_enabled = !unset;
+
        if (opts->call_graph == CALLCHAIN_NONE)
                opts->call_graph = CALLCHAIN_FP;
 
@@ -776,6 +782,16 @@ int record_callchain_opt(const struct option *opt,
        return 0;
 }
 
+static int perf_record_config(const char *var, const char *value, void *cb)
+{
+       struct record *rec = cb;
+
+       if (!strcmp(var, "record.call-graph"))
+               return record_parse_callchain(value, &rec->opts);
+
+       return perf_default_config(var, value, cb);
+}
+
 static const char * const record_usage[] = {
        "perf record [<options>] [<command>]",
        "perf record [<options>] -- <command> [<options>]",
@@ -807,7 +823,7 @@ static struct record record = {
 
 #define CALLCHAIN_HELP "setup and enables call-graph (stack chain/backtrace) recording: "
 
-#ifdef HAVE_LIBUNWIND_SUPPORT
+#ifdef HAVE_DWARF_UNWIND_SUPPORT
 const char record_callchain_help[] = CALLCHAIN_HELP "fp dwarf";
 #else
 const char record_callchain_help[] = CALLCHAIN_HELP "fp";
@@ -907,6 +923,8 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
        if (rec->evlist == NULL)
                return -ENOMEM;
 
+       perf_config(perf_record_config, rec);
+
        argc = parse_options(argc, argv, record_options, record_usage,
                            PARSE_OPT_STOP_AT_NON_OPTION);
        if (!argc && target__none(&rec->opts.target))
index 3c53ec2..d882b6f 100644 (file)
@@ -75,13 +75,10 @@ static int report__config(const char *var, const char *value, void *cb)
        return perf_default_config(var, value, cb);
 }
 
-static int report__add_mem_hist_entry(struct perf_tool *tool, struct addr_location *al,
-                                     struct perf_sample *sample, struct perf_evsel *evsel,
-                                     union perf_event *event)
+static int report__add_mem_hist_entry(struct report *rep, struct addr_location *al,
+                                     struct perf_sample *sample, struct perf_evsel *evsel)
 {
-       struct report *rep = container_of(tool, struct report, tool);
        struct symbol *parent = NULL;
-       u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
        struct hist_entry *he;
        struct mem_info *mi, *mx;
        uint64_t cost;
@@ -90,7 +87,7 @@ static int report__add_mem_hist_entry(struct perf_tool *tool, struct addr_locati
        if (err)
                return err;
 
-       mi = machine__resolve_mem(al->machine, al->thread, sample, cpumode);
+       mi = sample__resolve_mem(sample, al);
        if (!mi)
                return -ENOMEM;
 
@@ -129,10 +126,9 @@ out:
        return err;
 }
 
-static int report__add_branch_hist_entry(struct perf_tool *tool, struct addr_location *al,
+static int report__add_branch_hist_entry(struct report *rep, struct addr_location *al,
                                         struct perf_sample *sample, struct perf_evsel *evsel)
 {
-       struct report *rep = container_of(tool, struct report, tool);
        struct symbol *parent = NULL;
        unsigned i;
        struct hist_entry *he;
@@ -142,8 +138,7 @@ static int report__add_branch_hist_entry(struct perf_tool *tool, struct addr_loc
        if (err)
                return err;
 
-       bi = machine__resolve_bstack(al->machine, al->thread,
-                                    sample->branch_stack);
+       bi = sample__resolve_bstack(sample, al);
        if (!bi)
                return -ENOMEM;
 
@@ -184,10 +179,9 @@ out:
        return err;
 }
 
-static int report__add_hist_entry(struct perf_tool *tool, struct perf_evsel *evsel,
+static int report__add_hist_entry(struct report *rep, struct perf_evsel *evsel,
                                  struct addr_location *al, struct perf_sample *sample)
 {
-       struct report *rep = container_of(tool, struct report, tool);
        struct symbol *parent = NULL;
        struct hist_entry *he;
        int err = sample__resolve_callchain(sample, &parent, evsel, al, rep->max_stack);
@@ -236,18 +230,18 @@ static int process_sample_event(struct perf_tool *tool,
                return 0;
 
        if (sort__mode == SORT_MODE__BRANCH) {
-               ret = report__add_branch_hist_entry(tool, &al, sample, evsel);
+               ret = report__add_branch_hist_entry(rep, &al, sample, evsel);
                if (ret < 0)
                        pr_debug("problem adding lbr entry, skipping event\n");
        } else if (rep->mem_mode == 1) {
-               ret = report__add_mem_hist_entry(tool, &al, sample, evsel, event);
+               ret = report__add_mem_hist_entry(rep, &al, sample, evsel);
                if (ret < 0)
                        pr_debug("problem adding mem entry, skipping event\n");
        } else {
                if (al.map != NULL)
                        al.map->dso->hit = 1;
 
-               ret = report__add_hist_entry(tool, evsel, &al, sample);
+               ret = report__add_hist_entry(rep, evsel, &al, sample);
                if (ret < 0)
                        pr_debug("problem incrementing symbol period, skipping event\n");
        }
index 76cd510..ed99ec4 100644 (file)
@@ -991,6 +991,16 @@ parse_callchain_opt(const struct option *opt, const char *arg, int unset)
        return record_parse_callchain_opt(opt, arg, unset);
 }
 
+static int perf_top_config(const char *var, const char *value, void *cb)
+{
+       struct perf_top *top = cb;
+
+       if (!strcmp(var, "top.call-graph"))
+               return record_parse_callchain(value, &top->record_opts);
+
+       return perf_default_config(var, value, cb);
+}
+
 static int
 parse_percent_limit(const struct option *opt, const char *arg,
                    int unset __maybe_unused)
@@ -1115,6 +1125,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
        if (top.evlist == NULL)
                return -ENOMEM;
 
+       perf_config(perf_top_config, &top);
+
        argc = parse_options(argc, argv, options, top_usage, 0);
        if (argc)
                usage_with_options(top_usage, options);
index c48d449..1686583 100644 (file)
@@ -338,7 +338,7 @@ ifndef NO_LIBUNWIND
       CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME
     endif
 
-    CFLAGS += -DHAVE_LIBUNWIND_SUPPORT
+    CFLAGS += -DHAVE_DWARF_UNWIND_SUPPORT -DHAVE_LIBUNWIND_SUPPORT
     EXTLIBS += $(LIBUNWIND_LIBS)
     CFLAGS += $(LIBUNWIND_CFLAGS)
     LDFLAGS += $(LIBUNWIND_LDFLAGS)
index e84fa26..6898ad0 100644 (file)
@@ -251,12 +251,14 @@ void pthread__unblock_sigwinch(void);
 enum perf_call_graph_mode {
        CALLCHAIN_NONE,
        CALLCHAIN_FP,
-       CALLCHAIN_DWARF
+       CALLCHAIN_DWARF,
+       CALLCHAIN_MAX
 };
 
 struct record_opts {
        struct target target;
        int          call_graph;
+       bool         call_graph_enabled;
        bool         group;
        bool         inherit_stat;
        bool         no_buffering;
index 1e67437..b11bf8a 100644 (file)
@@ -115,6 +115,14 @@ static struct test {
                .desc = "Test parsing with no sample_id_all bit set",
                .func = test__parse_no_sample_id_all,
        },
+#if defined(__x86_64__) || defined(__i386__)
+#ifdef HAVE_DWARF_UNWIND_SUPPORT
+       {
+               .desc = "Test dwarf unwind",
+               .func = test__dwarf_unwind,
+       },
+#endif
+#endif
        {
                .func = NULL,
        },
diff --git a/tools/perf/tests/dwarf-unwind.c b/tools/perf/tests/dwarf-unwind.c
new file mode 100644 (file)
index 0000000..f16ea28
--- /dev/null
@@ -0,0 +1,144 @@
+#include <linux/compiler.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include "tests.h"
+#include "debug.h"
+#include "machine.h"
+#include "event.h"
+#include "unwind.h"
+#include "perf_regs.h"
+#include "map.h"
+#include "thread.h"
+
+static int mmap_handler(struct perf_tool *tool __maybe_unused,
+                       union perf_event *event,
+                       struct perf_sample *sample __maybe_unused,
+                       struct machine *machine)
+{
+       return machine__process_mmap_event(machine, event, NULL);
+}
+
+static int init_live_machine(struct machine *machine)
+{
+       union perf_event event;
+       pid_t pid = getpid();
+
+       return perf_event__synthesize_mmap_events(NULL, &event, pid, pid,
+                                                 mmap_handler, machine, true);
+}
+
+#define MAX_STACK 6
+
+static int unwind_entry(struct unwind_entry *entry, void *arg)
+{
+       unsigned long *cnt = (unsigned long *) arg;
+       char *symbol = entry->sym ? entry->sym->name : NULL;
+       static const char *funcs[MAX_STACK] = {
+               "test__arch_unwind_sample",
+               "unwind_thread",
+               "krava_3",
+               "krava_2",
+               "krava_1",
+               "test__dwarf_unwind"
+       };
+
+       if (*cnt >= MAX_STACK) {
+               pr_debug("failed: crossed the max stack value %d\n", MAX_STACK);
+               return -1;
+       }
+
+       if (!symbol) {
+               pr_debug("failed: got unresolved address 0x%" PRIx64 "\n",
+                        entry->ip);
+               return -1;
+       }
+
+       pr_debug("got: %s 0x%" PRIx64 "\n", symbol, entry->ip);
+       return strcmp((const char *) symbol, funcs[(*cnt)++]);
+}
+
+__attribute__ ((noinline))
+static int unwind_thread(struct thread *thread, struct machine *machine)
+{
+       struct perf_sample sample;
+       unsigned long cnt = 0;
+       int err = -1;
+
+       memset(&sample, 0, sizeof(sample));
+
+       if (test__arch_unwind_sample(&sample, thread)) {
+               pr_debug("failed to get unwind sample\n");
+               goto out;
+       }
+
+       err = unwind__get_entries(unwind_entry, &cnt, machine, thread,
+                                 &sample, MAX_STACK);
+       if (err)
+               pr_debug("unwind failed\n");
+       else if (cnt != MAX_STACK) {
+               pr_debug("got wrong number of stack entries %lu != %d\n",
+                        cnt, MAX_STACK);
+               err = -1;
+       }
+
+ out:
+       free(sample.user_stack.data);
+       free(sample.user_regs.regs);
+       return err;
+}
+
+__attribute__ ((noinline))
+static int krava_3(struct thread *thread, struct machine *machine)
+{
+       return unwind_thread(thread, machine);
+}
+
+__attribute__ ((noinline))
+static int krava_2(struct thread *thread, struct machine *machine)
+{
+       return krava_3(thread, machine);
+}
+
+__attribute__ ((noinline))
+static int krava_1(struct thread *thread, struct machine *machine)
+{
+       return krava_2(thread, machine);
+}
+
+int test__dwarf_unwind(void)
+{
+       struct machines machines;
+       struct machine *machine;
+       struct thread *thread;
+       int err = -1;
+
+       machines__init(&machines);
+
+       machine = machines__find(&machines, HOST_KERNEL_ID);
+       if (!machine) {
+               pr_err("Could not get machine\n");
+               return -1;
+       }
+
+       if (init_live_machine(machine)) {
+               pr_err("Could not init machine\n");
+               goto out;
+       }
+
+       if (verbose > 1)
+               machine__fprintf(machine, stderr);
+
+       thread = machine__find_thread(machine, getpid());
+       if (!thread) {
+               pr_err("Could not get thread\n");
+               goto out;
+       }
+
+       err = krava_1(thread, machine);
+
+ out:
+       machine__delete_threads(machine);
+       machine__exit(machine);
+       machines__exit(&machines);
+       return err;
+}
index 4db0ae6..8605ff5 100644 (file)
@@ -2,7 +2,7 @@
 #include "parse-events.h"
 #include "evsel.h"
 #include "evlist.h"
-#include "fs.h"
+#include <api/fs/fs.h>
 #include <api/fs/debugfs.h>
 #include "tests.h"
 #include <linux/hw_breakpoint.h>
index 1b67720..0014d3c 100644 (file)
@@ -22,8 +22,8 @@
 } while (0)
 
 static bool samples_same(const struct perf_sample *s1,
-                        const struct perf_sample *s2, u64 type, u64 regs_user,
-                        u64 read_format)
+                        const struct perf_sample *s2,
+                        u64 type, u64 read_format)
 {
        size_t i;
 
@@ -95,8 +95,9 @@ static bool samples_same(const struct perf_sample *s1,
        }
 
        if (type & PERF_SAMPLE_REGS_USER) {
-               size_t sz = hweight_long(regs_user) * sizeof(u64);
+               size_t sz = hweight_long(s1->user_regs.mask) * sizeof(u64);
 
+               COMP(user_regs.mask);
                COMP(user_regs.abi);
                if (s1->user_regs.abi &&
                    (!s1->user_regs.regs || !s2->user_regs.regs ||
@@ -174,6 +175,7 @@ static int do_test(u64 sample_type, u64 sample_regs_user, u64 read_format)
                .branch_stack   = &branch_stack.branch_stack,
                .user_regs      = {
                        .abi    = PERF_SAMPLE_REGS_ABI_64,
+                       .mask   = sample_regs_user,
                        .regs   = user_regs,
                },
                .user_stack     = {
@@ -201,8 +203,7 @@ static int do_test(u64 sample_type, u64 sample_regs_user, u64 read_format)
                sample.read.one.id    = 99;
        }
 
-       sz = perf_event__sample_event_size(&sample, sample_type,
-                                          sample_regs_user, read_format);
+       sz = perf_event__sample_event_size(&sample, sample_type, read_format);
        bufsz = sz + 4096; /* Add a bit for overrun checking */
        event = malloc(bufsz);
        if (!event) {
@@ -215,8 +216,7 @@ static int do_test(u64 sample_type, u64 sample_regs_user, u64 read_format)
        event->header.misc = 0;
        event->header.size = sz;
 
-       err = perf_event__synthesize_sample(event, sample_type,
-                                           sample_regs_user, read_format,
+       err = perf_event__synthesize_sample(event, sample_type, read_format,
                                            &sample, false);
        if (err) {
                pr_debug("%s failed for sample_type %#"PRIx64", error %d\n",
@@ -244,8 +244,7 @@ static int do_test(u64 sample_type, u64 sample_regs_user, u64 read_format)
                goto out_free;
        }
 
-       if (!samples_same(&sample, &sample_out, sample_type,
-                         sample_regs_user, read_format)) {
+       if (!samples_same(&sample, &sample_out, sample_type, read_format)) {
                pr_debug("parsing failed for sample_type %#"PRIx64"\n",
                         sample_type);
                goto out_free;
index e0ac713..a24795c 100644 (file)
@@ -40,5 +40,14 @@ int test__code_reading(void);
 int test__sample_parsing(void);
 int test__keep_tracking(void);
 int test__parse_no_sample_id_all(void);
+int test__dwarf_unwind(void);
 
+#if defined(__x86_64__) || defined(__i386__)
+#ifdef HAVE_DWARF_UNWIND_SUPPORT
+struct thread;
+struct perf_sample;
+int test__arch_unwind_sample(struct perf_sample *sample,
+                            struct thread *thread);
+#endif
+#endif
 #endif /* TESTS_H */
index a9b48c4..7fe4994 100644 (file)
@@ -1,5 +1,5 @@
 #include "util.h"
-#include "fs.h"
+#include <api/fs/fs.h>
 #include "../perf.h"
 #include "cpumap.h"
 #include <assert.h>
index cd7d6f0..ab06f1c 100644 (file)
@@ -102,6 +102,16 @@ struct dso {
        char             name[0];
 };
 
+/* dso__for_each_symbol - iterate over the symbols of given type
+ *
+ * @dso: the 'struct dso *' in which symbols itereated
+ * @pos: the 'struct symbol *' to use as a loop cursor
+ * @n: the 'struct rb_node *' to use as a temporary storage
+ * @type: the 'enum map_type' type of symbols
+ */
+#define dso__for_each_symbol(dso, pos, n, type)        \
+       symbols__for_each_entry(&(dso)->symbols[(type)], pos, n)
+
 static inline void dso__set_loaded(struct dso *dso, enum map_type type)
 {
        dso->loaded |= (1 << type);
index 851fa06..38457d4 100644 (file)
@@ -85,6 +85,7 @@ struct sample_event {
 
 struct regs_dump {
        u64 abi;
+       u64 mask;
        u64 *regs;
 };
 
@@ -259,9 +260,9 @@ int perf_event__preprocess_sample(const union perf_event *event,
 const char *perf_event__name(unsigned int id);
 
 size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type,
-                                    u64 sample_regs_user, u64 read_format);
+                                    u64 read_format);
 int perf_event__synthesize_sample(union perf_event *event, u64 type,
-                                 u64 sample_regs_user, u64 read_format,
+                                 u64 read_format,
                                  const struct perf_sample *sample,
                                  bool swapped);
 
index 55407c5..adc94dd 100644 (file)
@@ -595,7 +595,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
                attr->mmap_data = track;
        }
 
-       if (opts->call_graph) {
+       if (opts->call_graph_enabled) {
                perf_evsel__set_sample_bit(evsel, CALLCHAIN);
 
                if (opts->call_graph == CALLCHAIN_DWARF) {
@@ -1220,7 +1220,7 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
        memset(data, 0, sizeof(*data));
        data->cpu = data->pid = data->tid = -1;
        data->stream_id = data->id = data->time = -1ULL;
-       data->period = 1;
+       data->period = evsel->attr.sample_period;
        data->weight = 0;
 
        if (event->header.type != PERF_RECORD_SAMPLE) {
@@ -1396,10 +1396,11 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
                array++;
 
                if (data->user_regs.abi) {
-                       u64 regs_user = evsel->attr.sample_regs_user;
+                       u64 mask = evsel->attr.sample_regs_user;
 
-                       sz = hweight_long(regs_user) * sizeof(u64);
+                       sz = hweight_long(mask) * sizeof(u64);
                        OVERFLOW_CHECK(array, sz, max_size);
+                       data->user_regs.mask = mask;
                        data->user_regs.regs = (u64 *)array;
                        array = (void *)array + sz;
                }
@@ -1451,7 +1452,7 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
 }
 
 size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type,
-                                    u64 sample_regs_user, u64 read_format)
+                                    u64 read_format)
 {
        size_t sz, result = sizeof(struct sample_event);
 
@@ -1517,7 +1518,7 @@ size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type,
        if (type & PERF_SAMPLE_REGS_USER) {
                if (sample->user_regs.abi) {
                        result += sizeof(u64);
-                       sz = hweight_long(sample_regs_user) * sizeof(u64);
+                       sz = hweight_long(sample->user_regs.mask) * sizeof(u64);
                        result += sz;
                } else {
                        result += sizeof(u64);
@@ -1546,7 +1547,7 @@ size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type,
 }
 
 int perf_event__synthesize_sample(union perf_event *event, u64 type,
-                                 u64 sample_regs_user, u64 read_format,
+                                 u64 read_format,
                                  const struct perf_sample *sample,
                                  bool swapped)
 {
@@ -1687,7 +1688,7 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type,
        if (type & PERF_SAMPLE_REGS_USER) {
                if (sample->user_regs.abi) {
                        *array++ = sample->user_regs.abi;
-                       sz = hweight_long(sample_regs_user) * sizeof(u64);
+                       sz = hweight_long(sample->user_regs.mask) * sizeof(u64);
                        memcpy(array, sample->user_regs.regs, sz);
                        array = (void *)array + sz;
                } else {
diff --git a/tools/perf/util/fs.h b/tools/perf/util/fs.h
deleted file mode 100644 (file)
index 5e09ce1..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef __PERF_FS
-#define __PERF_FS
-
-const char *sysfs__mountpoint(void);
-const char *procfs__mountpoint(void);
-
-#endif /* __PERF_FS */
index e4e6249..0466efa 100644 (file)
@@ -290,7 +290,7 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template)
                if (he->branch_info) {
                        /*
                         * This branch info is (a part of) allocated from
-                        * machine__resolve_bstack() and will be freed after
+                        * sample__resolve_bstack() and will be freed after
                         * adding new entries.  So we need to save a copy.
                         */
                        he->branch_info = malloc(sizeof(*he->branch_info));
@@ -369,7 +369,7 @@ static struct hist_entry *add_hist_entry(struct hists *hists,
                        he_stat__add_period(&he->stat, period, weight);
 
                        /*
-                        * This mem info was allocated from machine__resolve_mem
+                        * This mem info was allocated from sample__resolve_mem
                         * and will not be used anymore.
                         */
                        zfree(&entry->mem_info);
diff --git a/tools/perf/util/include/linux/hash.h b/tools/perf/util/include/linux/hash.h
deleted file mode 100644 (file)
index 201f573..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-#include "../../../../include/linux/hash.h"
-
-#ifndef PERF_HASH_H
-#define PERF_HASH_H
-#endif
index 1d928a0..bfe0a2a 100644 (file)
@@ -1,5 +1,4 @@
 #include <linux/kernel.h>
-#include <linux/prefetch.h>
 
 #include "../../../../include/linux/list.h"
 
diff --git a/tools/perf/util/include/linux/prefetch.h b/tools/perf/util/include/linux/prefetch.h
deleted file mode 100644 (file)
index 7841e48..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef PERF_LINUX_PREFETCH_H
-#define PERF_LINUX_PREFETCH_H
-
-static inline void prefetch(void *a __attribute__((unused))) { }
-
-#endif
index c872991..ac37d78 100644 (file)
@@ -1238,37 +1238,35 @@ static void ip__resolve_data(struct machine *machine, struct thread *thread,
        ams->map = al.map;
 }
 
-struct mem_info *machine__resolve_mem(struct machine *machine,
-                                     struct thread *thr,
-                                     struct perf_sample *sample,
-                                     u8 cpumode)
+struct mem_info *sample__resolve_mem(struct perf_sample *sample,
+                                    struct addr_location *al)
 {
        struct mem_info *mi = zalloc(sizeof(*mi));
 
        if (!mi)
                return NULL;
 
-       ip__resolve_ams(machine, thr, &mi->iaddr, sample->ip);
-       ip__resolve_data(machine, thr, cpumode, &mi->daddr, sample->addr);
+       ip__resolve_ams(al->machine, al->thread, &mi->iaddr, sample->ip);
+       ip__resolve_data(al->machine, al->thread, al->cpumode,
+                        &mi->daddr, sample->addr);
        mi->data_src.val = sample->data_src;
 
        return mi;
 }
 
-struct branch_info *machine__resolve_bstack(struct machine *machine,
-                                           struct thread *thr,
-                                           struct branch_stack *bs)
+struct branch_info *sample__resolve_bstack(struct perf_sample *sample,
+                                          struct addr_location *al)
 {
-       struct branch_info *bi;
        unsigned int i;
+       const struct branch_stack *bs = sample->branch_stack;
+       struct branch_info *bi = calloc(bs->nr, sizeof(struct branch_info));
 
-       bi = calloc(bs->nr, sizeof(struct branch_info));
        if (!bi)
                return NULL;
 
        for (i = 0; i < bs->nr; i++) {
-               ip__resolve_ams(machine, thr, &bi[i].to, bs->entries[i].to);
-               ip__resolve_ams(machine, thr, &bi[i].from, bs->entries[i].from);
+               ip__resolve_ams(al->machine, al->thread, &bi[i].to, bs->entries[i].to);
+               ip__resolve_ams(al->machine, al->thread, &bi[i].from, bs->entries[i].from);
                bi[i].flags = bs->entries[i].flags;
        }
        return bi;
@@ -1385,8 +1383,7 @@ int machine__resolve_callchain(struct machine *machine,
                return 0;
 
        return unwind__get_entries(unwind_entry, &callchain_cursor, machine,
-                                  thread, evsel->attr.sample_regs_user,
-                                  sample, max_stack);
+                                  thread, sample, max_stack);
 
 }
 
index f77e91e..2e6c248 100644 (file)
@@ -91,12 +91,10 @@ void machine__delete_dead_threads(struct machine *machine);
 void machine__delete_threads(struct machine *machine);
 void machine__delete(struct machine *machine);
 
-struct branch_info *machine__resolve_bstack(struct machine *machine,
-                                           struct thread *thread,
-                                           struct branch_stack *bs);
-struct mem_info *machine__resolve_mem(struct machine *machine,
-                                     struct thread *thread,
-                                     struct perf_sample *sample, u8 cpumode);
+struct branch_info *sample__resolve_bstack(struct perf_sample *sample,
+                                          struct addr_location *al);
+struct mem_info *sample__resolve_mem(struct perf_sample *sample,
+                                    struct addr_location *al);
 int machine__resolve_callchain(struct machine *machine,
                               struct perf_evsel *evsel,
                               struct thread *thread,
index 257e513..f00f058 100644 (file)
@@ -90,6 +90,16 @@ u64 map__objdump_2mem(struct map *map, u64 ip);
 
 struct symbol;
 
+/* map__for_each_symbol - iterate over the symbols in the given map
+ *
+ * @map: the 'struct map *' in which symbols itereated
+ * @pos: the 'struct symbol *' to use as a loop cursor
+ * @n: the 'struct rb_node *' to use as a temporary storage
+ * Note: caller must ensure map->dso is not NULL (map is loaded).
+ */
+#define map__for_each_symbol(map, pos, n)      \
+       dso__for_each_symbol(map->dso, pos, n, map->type)
+
 typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym);
 
 void map__init(struct map *map, enum map_type type,
diff --git a/tools/perf/util/perf_regs.c b/tools/perf/util/perf_regs.c
new file mode 100644 (file)
index 0000000..a3539ef
--- /dev/null
@@ -0,0 +1,19 @@
+#include <errno.h>
+#include "perf_regs.h"
+
+int perf_reg_value(u64 *valp, struct regs_dump *regs, int id)
+{
+       int i, idx = 0;
+       u64 mask = regs->mask;
+
+       if (!(mask & (1 << id)))
+               return -EINVAL;
+
+       for (i = 0; i < id; i++) {
+               if (mask & (1 << i))
+                       idx++;
+       }
+
+       *valp = regs->regs[idx];
+       return 0;
+}
index a3d42cd..d6e8b6a 100644 (file)
@@ -1,8 +1,14 @@
 #ifndef __PERF_REGS_H
 #define __PERF_REGS_H
 
+#include "types.h"
+#include "event.h"
+
 #ifdef HAVE_PERF_REGS_SUPPORT
 #include <perf_regs.h>
+
+int perf_reg_value(u64 *valp, struct regs_dump *regs, int id);
+
 #else
 #define PERF_REGS_MASK 0
 
@@ -10,5 +16,12 @@ static inline const char *perf_reg_name(int id __maybe_unused)
 {
        return NULL;
 }
+
+static inline int perf_reg_value(u64 *valp __maybe_unused,
+                                struct regs_dump *regs __maybe_unused,
+                                int id __maybe_unused)
+{
+       return 0;
+}
 #endif /* HAVE_PERF_REGS_SUPPORT */
 #endif /* __PERF_REGS_H */
index b752ecb..00a7dcb 100644 (file)
@@ -3,7 +3,7 @@
 #include <unistd.h>
 #include <stdio.h>
 #include <dirent.h>
-#include "fs.h"
+#include <api/fs/fs.h>
 #include <locale.h>
 #include "util.h"
 #include "pmu.h"
index d8b048c..0d1542f 100644 (file)
@@ -70,34 +70,32 @@ static int e_snprintf(char *str, size_t size, const char *format, ...)
 }
 
 static char *synthesize_perf_probe_point(struct perf_probe_point *pp);
-static int convert_name_to_addr(struct perf_probe_event *pev,
-                               const char *exec);
 static void clear_probe_trace_event(struct probe_trace_event *tev);
-static struct machine machine;
+static struct machine *host_machine;
 
 /* Initialize symbol maps and path of vmlinux/modules */
-static int init_vmlinux(void)
+static int init_symbol_maps(bool user_only)
 {
        int ret;
 
        symbol_conf.sort_by_name = true;
-       if (symbol_conf.vmlinux_name == NULL)
-               symbol_conf.try_vmlinux_path = true;
-       else
-               pr_debug("Use vmlinux: %s\n", symbol_conf.vmlinux_name);
        ret = symbol__init();
        if (ret < 0) {
                pr_debug("Failed to init symbol map.\n");
                goto out;
        }
 
-       ret = machine__init(&machine, "", HOST_KERNEL_ID);
-       if (ret < 0)
-               goto out;
+       if (host_machine || user_only)  /* already initialized */
+               return 0;
 
-       if (machine__create_kernel_maps(&machine) < 0) {
-               pr_debug("machine__create_kernel_maps() failed.\n");
-               goto out;
+       if (symbol_conf.vmlinux_name)
+               pr_debug("Use vmlinux: %s\n", symbol_conf.vmlinux_name);
+
+       host_machine = machine__new_host();
+       if (!host_machine) {
+               pr_debug("machine__new_host() failed.\n");
+               symbol__exit();
+               ret = -1;
        }
 out:
        if (ret < 0)
@@ -105,21 +103,66 @@ out:
        return ret;
 }
 
+static void exit_symbol_maps(void)
+{
+       if (host_machine) {
+               machine__delete(host_machine);
+               host_machine = NULL;
+       }
+       symbol__exit();
+}
+
 static struct symbol *__find_kernel_function_by_name(const char *name,
                                                     struct map **mapp)
 {
-       return machine__find_kernel_function_by_name(&machine, name, mapp,
+       return machine__find_kernel_function_by_name(host_machine, name, mapp,
                                                     NULL);
 }
 
+static struct symbol *__find_kernel_function(u64 addr, struct map **mapp)
+{
+       return machine__find_kernel_function(host_machine, addr, mapp, NULL);
+}
+
+static struct ref_reloc_sym *kernel_get_ref_reloc_sym(void)
+{
+       /* kmap->ref_reloc_sym should be set if host_machine is initialized */
+       struct kmap *kmap;
+
+       if (map__load(host_machine->vmlinux_maps[MAP__FUNCTION], NULL) < 0)
+               return NULL;
+
+       kmap = map__kmap(host_machine->vmlinux_maps[MAP__FUNCTION]);
+       return kmap->ref_reloc_sym;
+}
+
+static u64 kernel_get_symbol_address_by_name(const char *name, bool reloc)
+{
+       struct ref_reloc_sym *reloc_sym;
+       struct symbol *sym;
+       struct map *map;
+
+       /* ref_reloc_sym is just a label. Need a special fix*/
+       reloc_sym = kernel_get_ref_reloc_sym();
+       if (reloc_sym && strcmp(name, reloc_sym->name) == 0)
+               return (reloc) ? reloc_sym->addr : reloc_sym->unrelocated_addr;
+       else {
+               sym = __find_kernel_function_by_name(name, &map);
+               if (sym)
+                       return map->unmap_ip(map, sym->start) -
+                               (reloc) ? 0 : map->reloc;
+       }
+       return 0;
+}
+
 static struct map *kernel_get_module_map(const char *module)
 {
        struct rb_node *nd;
-       struct map_groups *grp = &machine.kmaps;
+       struct map_groups *grp = &host_machine->kmaps;
 
        /* A file path -- this is an offline module */
        if (module && strchr(module, '/'))
-               return machine__new_module(&machine, 0, module);
+               return machine__new_module(host_machine, 0, module);
 
        if (!module)
                module = "kernel";
@@ -141,7 +184,7 @@ static struct dso *kernel_get_module_dso(const char *module)
        const char *vmlinux_name;
 
        if (module) {
-               list_for_each_entry(dso, &machine.kernel_dsos, node) {
+               list_for_each_entry(dso, &host_machine->kernel_dsos, node) {
                        if (strncmp(dso->short_name + 1, module,
                                    dso->short_name_len - 2) == 0)
                                goto found;
@@ -150,7 +193,7 @@ static struct dso *kernel_get_module_dso(const char *module)
                return NULL;
        }
 
-       map = machine.vmlinux_maps[MAP__FUNCTION];
+       map = host_machine->vmlinux_maps[MAP__FUNCTION];
        dso = map->dso;
 
        vmlinux_name = symbol_conf.vmlinux_name;
@@ -173,20 +216,6 @@ const char *kernel_get_module_path(const char *module)
        return (dso) ? dso->long_name : NULL;
 }
 
-static int init_user_exec(void)
-{
-       int ret = 0;
-
-       symbol_conf.try_vmlinux_path = false;
-       symbol_conf.sort_by_name = true;
-       ret = symbol__init();
-
-       if (ret < 0)
-               pr_debug("Failed to init symbol map.\n");
-
-       return ret;
-}
-
 static int convert_exec_to_group(const char *exec, char **result)
 {
        char *ptr1, *ptr2, *exec_copy;
@@ -218,32 +247,23 @@ out:
        return ret;
 }
 
-static int convert_to_perf_probe_point(struct probe_trace_point *tp,
-                                       struct perf_probe_point *pp)
+static void clear_probe_trace_events(struct probe_trace_event *tevs, int ntevs)
 {
-       pp->function = strdup(tp->symbol);
-
-       if (pp->function == NULL)
-               return -ENOMEM;
-
-       pp->offset = tp->offset;
-       pp->retprobe = tp->retprobe;
+       int i;
 
-       return 0;
+       for (i = 0; i < ntevs; i++)
+               clear_probe_trace_event(tevs + i);
 }
 
 #ifdef HAVE_DWARF_SUPPORT
+
 /* Open new debuginfo of given module */
 static struct debuginfo *open_debuginfo(const char *module)
 {
-       const char *path;
+       const char *path = module;
 
-       /* A file path -- this is an offline module */
-       if (module && strchr(module, '/'))
-               path = module;
-       else {
+       if (!module || !strchr(module, '/')) {
                path = kernel_get_module_path(module);
-
                if (!path) {
                        pr_err("Failed to find path of %s module.\n",
                               module ?: "kernel");
@@ -253,46 +273,6 @@ static struct debuginfo *open_debuginfo(const char *module)
        return debuginfo__new(path);
 }
 
-/*
- * Convert trace point to probe point with debuginfo
- * Currently only handles kprobes.
- */
-static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
-                                       struct perf_probe_point *pp)
-{
-       struct symbol *sym;
-       struct map *map;
-       u64 addr;
-       int ret = -ENOENT;
-       struct debuginfo *dinfo;
-
-       sym = __find_kernel_function_by_name(tp->symbol, &map);
-       if (sym) {
-               addr = map->unmap_ip(map, sym->start + tp->offset);
-               pr_debug("try to find %s+%ld@%" PRIx64 "\n", tp->symbol,
-                        tp->offset, addr);
-
-               dinfo = debuginfo__new_online_kernel(addr);
-               if (dinfo) {
-                       ret = debuginfo__find_probe_point(dinfo,
-                                                (unsigned long)addr, pp);
-                       debuginfo__delete(dinfo);
-               } else {
-                       pr_debug("Failed to open debuginfo at 0x%" PRIx64 "\n",
-                                addr);
-                       ret = -ENOENT;
-               }
-       }
-       if (ret <= 0) {
-               pr_debug("Failed to find corresponding probes from "
-                        "debuginfo. Use kprobe event information.\n");
-               return convert_to_perf_probe_point(tp, pp);
-       }
-       pp->retprobe = tp->retprobe;
-
-       return 0;
-}
-
 static int get_text_start_address(const char *exec, unsigned long *address)
 {
        Elf *elf;
@@ -321,12 +301,62 @@ out:
        return ret;
 }
 
+/*
+ * Convert trace point to probe point with debuginfo
+ */
+static int find_perf_probe_point_from_dwarf(struct probe_trace_point *tp,
+                                           struct perf_probe_point *pp,
+                                           bool is_kprobe)
+{
+       struct debuginfo *dinfo = NULL;
+       unsigned long stext = 0;
+       u64 addr = tp->address;
+       int ret = -ENOENT;
+
+       /* convert the address to dwarf address */
+       if (!is_kprobe) {
+               if (!addr) {
+                       ret = -EINVAL;
+                       goto error;
+               }
+               ret = get_text_start_address(tp->module, &stext);
+               if (ret < 0)
+                       goto error;
+               addr += stext;
+       } else {
+               addr = kernel_get_symbol_address_by_name(tp->symbol, false);
+               if (addr == 0)
+                       goto error;
+               addr += tp->offset;
+       }
+
+       pr_debug("try to find information at %" PRIx64 " in %s\n", addr,
+                tp->module ? : "kernel");
+
+       dinfo = open_debuginfo(tp->module);
+       if (dinfo) {
+               ret = debuginfo__find_probe_point(dinfo,
+                                                (unsigned long)addr, pp);
+               debuginfo__delete(dinfo);
+       } else {
+               pr_debug("Failed to open debuginfo at 0x%" PRIx64 "\n", addr);
+               ret = -ENOENT;
+       }
+
+       if (ret > 0) {
+               pp->retprobe = tp->retprobe;
+               return 0;
+       }
+error:
+       pr_debug("Failed to find corresponding probes from debuginfo.\n");
+       return ret ? : -ENOENT;
+}
+
 static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs,
                                          int ntevs, const char *exec)
 {
        int i, ret = 0;
-       unsigned long offset, stext = 0;
-       char buf[32];
+       unsigned long stext = 0;
 
        if (!exec)
                return 0;
@@ -337,15 +367,9 @@ static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs,
 
        for (i = 0; i < ntevs && ret >= 0; i++) {
                /* point.address is the addres of point.symbol + point.offset */
-               offset = tevs[i].point.address - stext;
-               tevs[i].point.offset = 0;
-               zfree(&tevs[i].point.symbol);
-               ret = e_snprintf(buf, 32, "0x%lx", offset);
-               if (ret < 0)
-                       break;
+               tevs[i].point.address -= stext;
                tevs[i].point.module = strdup(exec);
-               tevs[i].point.symbol = strdup(buf);
-               if (!tevs[i].point.symbol || !tevs[i].point.module) {
+               if (!tevs[i].point.module) {
                        ret = -ENOMEM;
                        break;
                }
@@ -388,12 +412,40 @@ static int add_module_to_probe_trace_events(struct probe_trace_event *tevs,
        return ret;
 }
 
-static void clear_probe_trace_events(struct probe_trace_event *tevs, int ntevs)
+/* Post processing the probe events */
+static int post_process_probe_trace_events(struct probe_trace_event *tevs,
+                                          int ntevs, const char *module,
+                                          bool uprobe)
 {
+       struct ref_reloc_sym *reloc_sym;
+       char *tmp;
        int i;
 
-       for (i = 0; i < ntevs; i++)
-               clear_probe_trace_event(tevs + i);
+       if (uprobe)
+               return add_exec_to_probe_trace_events(tevs, ntevs, module);
+
+       /* Note that currently ref_reloc_sym based probe is not for drivers */
+       if (module)
+               return add_module_to_probe_trace_events(tevs, ntevs, module);
+
+       reloc_sym = kernel_get_ref_reloc_sym();
+       if (!reloc_sym) {
+               pr_warning("Relocated base symbol is not found!\n");
+               return -EINVAL;
+       }
+
+       for (i = 0; i < ntevs; i++) {
+               if (tevs[i].point.address) {
+                       tmp = strdup(reloc_sym->name);
+                       if (!tmp)
+                               return -ENOMEM;
+                       free(tevs[i].point.symbol);
+                       tevs[i].point.symbol = tmp;
+                       tevs[i].point.offset = tevs[i].point.address -
+                                              reloc_sym->unrelocated_addr;
+               }
+       }
+       return 0;
 }
 
 /* Try to find perf_probe_event with debuginfo */
@@ -416,21 +468,16 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
                return 0;
        }
 
+       pr_debug("Try to find probe point from debuginfo.\n");
        /* Searching trace events corresponding to a probe event */
        ntevs = debuginfo__find_trace_events(dinfo, pev, tevs, max_tevs);
 
        debuginfo__delete(dinfo);
 
        if (ntevs > 0) {        /* Succeeded to find trace events */
-               pr_debug("find %d probe_trace_events.\n", ntevs);
-               if (target) {
-                       if (pev->uprobes)
-                               ret = add_exec_to_probe_trace_events(*tevs,
-                                                ntevs, target);
-                       else
-                               ret = add_module_to_probe_trace_events(*tevs,
-                                                ntevs, target);
-               }
+               pr_debug("Found %d probe_trace_events.\n", ntevs);
+               ret = post_process_probe_trace_events(*tevs, ntevs,
+                                                       target, pev->uprobes);
                if (ret < 0) {
                        clear_probe_trace_events(*tevs, ntevs);
                        zfree(tevs);
@@ -563,20 +610,16 @@ static int _show_one_line(FILE *fp, int l, bool skip, bool show_num)
  * Show line-range always requires debuginfo to find source file and
  * line number.
  */
-int show_line_range(struct line_range *lr, const char *module)
+static int __show_line_range(struct line_range *lr, const char *module)
 {
        int l = 1;
-       struct line_node *ln;
+       struct int_node *ln;
        struct debuginfo *dinfo;
        FILE *fp;
        int ret;
        char *tmp;
 
        /* Search a line range */
-       ret = init_vmlinux();
-       if (ret < 0)
-               return ret;
-
        dinfo = open_debuginfo(module);
        if (!dinfo) {
                pr_warning("Failed to open debuginfo file.\n");
@@ -623,8 +666,8 @@ int show_line_range(struct line_range *lr, const char *module)
                        goto end;
        }
 
-       list_for_each_entry(ln, &lr->line_list, list) {
-               for (; ln->line > l; l++) {
+       intlist__for_each(ln, lr->line_list) {
+               for (; ln->i > l; l++) {
                        ret = show_one_line(fp, l - lr->offset);
                        if (ret < 0)
                                goto end;
@@ -646,6 +689,19 @@ end:
        return ret;
 }
 
+int show_line_range(struct line_range *lr, const char *module)
+{
+       int ret;
+
+       ret = init_symbol_maps(false);
+       if (ret < 0)
+               return ret;
+       ret = __show_line_range(lr, module);
+       exit_symbol_maps();
+
+       return ret;
+}
+
 static int show_available_vars_at(struct debuginfo *dinfo,
                                  struct perf_probe_event *pev,
                                  int max_vls, struct strfilter *_filter,
@@ -707,14 +763,15 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs,
        int i, ret = 0;
        struct debuginfo *dinfo;
 
-       ret = init_vmlinux();
+       ret = init_symbol_maps(false);
        if (ret < 0)
                return ret;
 
        dinfo = open_debuginfo(module);
        if (!dinfo) {
                pr_warning("Failed to open debuginfo file.\n");
-               return -ENOENT;
+               ret = -ENOENT;
+               goto out;
        }
 
        setup_pager();
@@ -724,23 +781,19 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs,
                                             externs);
 
        debuginfo__delete(dinfo);
+out:
+       exit_symbol_maps();
        return ret;
 }
 
 #else  /* !HAVE_DWARF_SUPPORT */
 
-static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
-                                       struct perf_probe_point *pp)
+static int
+find_perf_probe_point_from_dwarf(struct probe_trace_point *tp __maybe_unused,
+                                struct perf_probe_point *pp __maybe_unused,
+                                bool is_kprobe __maybe_unused)
 {
-       struct symbol *sym;
-
-       sym = __find_kernel_function_by_name(tp->symbol, NULL);
-       if (!sym) {
-               pr_err("Failed to find symbol %s in kernel.\n", tp->symbol);
-               return -ENOENT;
-       }
-
-       return convert_to_perf_probe_point(tp, pp);
+       return -ENOSYS;
 }
 
 static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
@@ -776,24 +829,22 @@ int show_available_vars(struct perf_probe_event *pevs __maybe_unused,
 
 void line_range__clear(struct line_range *lr)
 {
-       struct line_node *ln;
-
        free(lr->function);
        free(lr->file);
        free(lr->path);
        free(lr->comp_dir);
-       while (!list_empty(&lr->line_list)) {
-               ln = list_first_entry(&lr->line_list, struct line_node, list);
-               list_del(&ln->list);
-               free(ln);
-       }
+       intlist__delete(lr->line_list);
        memset(lr, 0, sizeof(*lr));
 }
 
-void line_range__init(struct line_range *lr)
+int line_range__init(struct line_range *lr)
 {
        memset(lr, 0, sizeof(*lr));
-       INIT_LIST_HEAD(&lr->line_list);
+       lr->line_list = intlist__new(NULL);
+       if (!lr->line_list)
+               return -ENOMEM;
+       else
+               return 0;
 }
 
 static int parse_line_num(char **ptr, int *val, const char *what)
@@ -1267,16 +1318,21 @@ static int parse_probe_trace_command(const char *cmd,
        } else
                p = argv[1];
        fmt1_str = strtok_r(p, "+", &fmt);
-       tp->symbol = strdup(fmt1_str);
-       if (tp->symbol == NULL) {
-               ret = -ENOMEM;
-               goto out;
+       if (fmt1_str[0] == '0') /* only the address started with 0x */
+               tp->address = strtoul(fmt1_str, NULL, 0);
+       else {
+               /* Only the symbol-based probe has offset */
+               tp->symbol = strdup(fmt1_str);
+               if (tp->symbol == NULL) {
+                       ret = -ENOMEM;
+                       goto out;
+               }
+               fmt2_str = strtok_r(NULL, "", &fmt);
+               if (fmt2_str == NULL)
+                       tp->offset = 0;
+               else
+                       tp->offset = strtoul(fmt2_str, NULL, 10);
        }
-       fmt2_str = strtok_r(NULL, "", &fmt);
-       if (fmt2_str == NULL)
-               tp->offset = 0;
-       else
-               tp->offset = strtoul(fmt2_str, NULL, 10);
 
        tev->nargs = argc - 2;
        tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs);
@@ -1518,20 +1574,27 @@ char *synthesize_probe_trace_command(struct probe_trace_event *tev)
        if (buf == NULL)
                return NULL;
 
+       len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s ", tp->retprobe ? 'r' : 'p',
+                        tev->group, tev->event);
+       if (len <= 0)
+               goto error;
+
+       /* Uprobes must have tp->address and tp->module */
+       if (tev->uprobes && (!tp->address || !tp->module))
+               goto error;
+
+       /* Use the tp->address for uprobes */
        if (tev->uprobes)
-               len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s:%s",
-                                tp->retprobe ? 'r' : 'p',
-                                tev->group, tev->event,
-                                tp->module, tp->symbol);
+               ret = e_snprintf(buf + len, MAX_CMDLEN - len, "%s:0x%lx",
+                                tp->module, tp->address);
        else
-               len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s%s%s+%lu",
-                                tp->retprobe ? 'r' : 'p',
-                                tev->group, tev->event,
+               ret = e_snprintf(buf + len, MAX_CMDLEN - len, "%s%s%s+%lu",
                                 tp->module ?: "", tp->module ? ":" : "",
                                 tp->symbol, tp->offset);
 
-       if (len <= 0)
+       if (ret <= 0)
                goto error;
+       len += ret;
 
        for (i = 0; i < tev->nargs; i++) {
                ret = synthesize_probe_trace_arg(&tev->args[i], buf + len,
@@ -1547,6 +1610,79 @@ error:
        return NULL;
 }
 
+static int find_perf_probe_point_from_map(struct probe_trace_point *tp,
+                                         struct perf_probe_point *pp,
+                                         bool is_kprobe)
+{
+       struct symbol *sym = NULL;
+       struct map *map;
+       u64 addr;
+       int ret = -ENOENT;
+
+       if (!is_kprobe) {
+               map = dso__new_map(tp->module);
+               if (!map)
+                       goto out;
+               addr = tp->address;
+               sym = map__find_symbol(map, addr, NULL);
+       } else {
+               addr = kernel_get_symbol_address_by_name(tp->symbol, true);
+               if (addr) {
+                       addr += tp->offset;
+                       sym = __find_kernel_function(addr, &map);
+               }
+       }
+       if (!sym)
+               goto out;
+
+       pp->retprobe = tp->retprobe;
+       pp->offset = addr - map->unmap_ip(map, sym->start);
+       pp->function = strdup(sym->name);
+       ret = pp->function ? 0 : -ENOMEM;
+
+out:
+       if (map && !is_kprobe) {
+               dso__delete(map->dso);
+               map__delete(map);
+       }
+
+       return ret;
+}
+
+static int convert_to_perf_probe_point(struct probe_trace_point *tp,
+                                       struct perf_probe_point *pp,
+                                       bool is_kprobe)
+{
+       char buf[128];
+       int ret;
+
+       ret = find_perf_probe_point_from_dwarf(tp, pp, is_kprobe);
+       if (!ret)
+               return 0;
+       ret = find_perf_probe_point_from_map(tp, pp, is_kprobe);
+       if (!ret)
+               return 0;
+
+       pr_debug("Failed to find probe point from both of dwarf and map.\n");
+
+       if (tp->symbol) {
+               pp->function = strdup(tp->symbol);
+               pp->offset = tp->offset;
+       } else if (!tp->module && !is_kprobe) {
+               ret = e_snprintf(buf, 128, "0x%" PRIx64, (u64)tp->address);
+               if (ret < 0)
+                       return ret;
+               pp->function = strdup(buf);
+               pp->offset = 0;
+       }
+       if (pp->function == NULL)
+               return -ENOMEM;
+
+       pp->retprobe = tp->retprobe;
+
+       return 0;
+}
+
 static int convert_to_perf_probe_event(struct probe_trace_event *tev,
                               struct perf_probe_event *pev, bool is_kprobe)
 {
@@ -1560,11 +1696,7 @@ static int convert_to_perf_probe_event(struct probe_trace_event *tev,
                return -ENOMEM;
 
        /* Convert trace_point to probe_point */
-       if (is_kprobe)
-               ret = kprobe_convert_to_perf_probe(&tev->point, &pev->point);
-       else
-               ret = convert_to_perf_probe_point(&tev->point, &pev->point);
-
+       ret = convert_to_perf_probe_point(&tev->point, &pev->point, is_kprobe);
        if (ret < 0)
                return ret;
 
@@ -1731,7 +1863,8 @@ static struct strlist *get_probe_trace_command_rawlist(int fd)
 }
 
 /* Show an event */
-static int show_perf_probe_event(struct perf_probe_event *pev)
+static int show_perf_probe_event(struct perf_probe_event *pev,
+                                const char *module)
 {
        int i, ret;
        char buf[128];
@@ -1747,6 +1880,8 @@ static int show_perf_probe_event(struct perf_probe_event *pev)
                return ret;
 
        printf("  %-20s (on %s", buf, place);
+       if (module)
+               printf(" in %s", module);
 
        if (pev->nargs > 0) {
                printf(" with");
@@ -1784,7 +1919,8 @@ static int __show_perf_probe_events(int fd, bool is_kprobe)
                        ret = convert_to_perf_probe_event(&tev, &pev,
                                                                is_kprobe);
                        if (ret >= 0)
-                               ret = show_perf_probe_event(&pev);
+                               ret = show_perf_probe_event(&pev,
+                                                           tev.point.module);
                }
                clear_perf_probe_event(&pev);
                clear_probe_trace_event(&tev);
@@ -1807,7 +1943,7 @@ int show_perf_probe_events(void)
        if (fd < 0)
                return fd;
 
-       ret = init_vmlinux();
+       ret = init_symbol_maps(false);
        if (ret < 0)
                return ret;
 
@@ -1820,6 +1956,7 @@ int show_perf_probe_events(void)
                close(fd);
        }
 
+       exit_symbol_maps();
        return ret;
 }
 
@@ -1982,7 +2119,7 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
                group = pev->group;
                pev->event = tev->event;
                pev->group = tev->group;
-               show_perf_probe_event(pev);
+               show_perf_probe_event(pev, tev->point.module);
                /* Trick here - restore current event/group */
                pev->event = (char *)event;
                pev->group = (char *)group;
@@ -2008,113 +2145,175 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
        return ret;
 }
 
-static int convert_to_probe_trace_events(struct perf_probe_event *pev,
-                                         struct probe_trace_event **tevs,
-                                         int max_tevs, const char *target)
+static char *looking_function_name;
+static int num_matched_functions;
+
+static int probe_function_filter(struct map *map __maybe_unused,
+                                     struct symbol *sym)
 {
+       if ((sym->binding == STB_GLOBAL || sym->binding == STB_LOCAL) &&
+           strcmp(looking_function_name, sym->name) == 0) {
+               num_matched_functions++;
+               return 0;
+       }
+       return 1;
+}
+
+#define strdup_or_goto(str, label)     \
+       ({ char *__p = strdup(str); if (!__p) goto label; __p; })
+
+/*
+ * Find probe function addresses from map.
+ * Return an error or the number of found probe_trace_event
+ */
+static int find_probe_trace_events_from_map(struct perf_probe_event *pev,
+                                           struct probe_trace_event **tevs,
+                                           int max_tevs, const char *target)
+{
+       struct map *map = NULL;
+       struct kmap *kmap = NULL;
+       struct ref_reloc_sym *reloc_sym = NULL;
        struct symbol *sym;
-       int ret, i;
+       struct rb_node *nd;
        struct probe_trace_event *tev;
+       struct perf_probe_point *pp = &pev->point;
+       struct probe_trace_point *tp;
+       int ret, i;
 
-       if (pev->uprobes && !pev->group) {
-               /* Replace group name if not given */
-               ret = convert_exec_to_group(target, &pev->group);
-               if (ret != 0) {
-                       pr_warning("Failed to make a group name.\n");
-                       return ret;
-               }
+       /* Init maps of given executable or kernel */
+       if (pev->uprobes)
+               map = dso__new_map(target);
+       else
+               map = kernel_get_module_map(target);
+       if (!map) {
+               ret = -EINVAL;
+               goto out;
        }
 
-       /* Convert perf_probe_event with debuginfo */
-       ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, target);
-       if (ret != 0)
-               return ret;     /* Found in debuginfo or got an error */
-
-       if (pev->uprobes) {
-               ret = convert_name_to_addr(pev, target);
-               if (ret < 0)
-                       return ret;
+       /*
+        * Load matched symbols: Since the different local symbols may have
+        * same name but different addresses, this lists all the symbols.
+        */
+       num_matched_functions = 0;
+       looking_function_name = pp->function;
+       ret = map__load(map, probe_function_filter);
+       if (ret || num_matched_functions == 0) {
+               pr_err("Failed to find symbol %s in %s\n", pp->function,
+                       target ? : "kernel");
+               ret = -ENOENT;
+               goto out;
+       } else if (num_matched_functions > max_tevs) {
+               pr_err("Too many functions matched in %s\n",
+                       target ? : "kernel");
+               ret = -E2BIG;
+               goto out;
        }
 
-       /* Allocate trace event buffer */
-       tev = *tevs = zalloc(sizeof(struct probe_trace_event));
-       if (tev == NULL)
-               return -ENOMEM;
+       if (!pev->uprobes) {
+               kmap = map__kmap(map);
+               reloc_sym = kmap->ref_reloc_sym;
+               if (!reloc_sym) {
+                       pr_warning("Relocated base symbol is not found!\n");
+                       ret = -EINVAL;
+                       goto out;
+               }
+       }
 
-       /* Copy parameters */
-       tev->point.symbol = strdup(pev->point.function);
-       if (tev->point.symbol == NULL) {
+       /* Setup result trace-probe-events */
+       *tevs = zalloc(sizeof(*tev) * num_matched_functions);
+       if (!*tevs) {
                ret = -ENOMEM;
-               goto error;
+               goto out;
        }
 
-       if (target) {
-               tev->point.module = strdup(target);
-               if (tev->point.module == NULL) {
-                       ret = -ENOMEM;
-                       goto error;
+       ret = 0;
+       map__for_each_symbol(map, sym, nd) {
+               tev = (*tevs) + ret;
+               tp = &tev->point;
+               if (ret == num_matched_functions) {
+                       pr_warning("Too many symbols are listed. Skip it.\n");
+                       break;
                }
-       }
-
-       tev->point.offset = pev->point.offset;
-       tev->point.retprobe = pev->point.retprobe;
-       tev->nargs = pev->nargs;
-       tev->uprobes = pev->uprobes;
+               ret++;
 
-       if (tev->nargs) {
-               tev->args = zalloc(sizeof(struct probe_trace_arg)
-                                  * tev->nargs);
-               if (tev->args == NULL) {
-                       ret = -ENOMEM;
-                       goto error;
+               if (pp->offset > sym->end - sym->start) {
+                       pr_warning("Offset %ld is bigger than the size of %s\n",
+                                  pp->offset, sym->name);
+                       ret = -ENOENT;
+                       goto err_out;
+               }
+               /* Add one probe point */
+               tp->address = map->unmap_ip(map, sym->start) + pp->offset;
+               if (reloc_sym) {
+                       tp->symbol = strdup_or_goto(reloc_sym->name, nomem_out);
+                       tp->offset = tp->address - reloc_sym->addr;
+               } else {
+                       tp->symbol = strdup_or_goto(sym->name, nomem_out);
+                       tp->offset = pp->offset;
+               }
+               tp->retprobe = pp->retprobe;
+               if (target)
+                       tev->point.module = strdup_or_goto(target, nomem_out);
+               tev->uprobes = pev->uprobes;
+               tev->nargs = pev->nargs;
+               if (tev->nargs) {
+                       tev->args = zalloc(sizeof(struct probe_trace_arg) *
+                                          tev->nargs);
+                       if (tev->args == NULL)
+                               goto nomem_out;
                }
                for (i = 0; i < tev->nargs; i++) {
-                       if (pev->args[i].name) {
-                               tev->args[i].name = strdup(pev->args[i].name);
-                               if (tev->args[i].name == NULL) {
-                                       ret = -ENOMEM;
-                                       goto error;
-                               }
-                       }
-                       tev->args[i].value = strdup(pev->args[i].var);
-                       if (tev->args[i].value == NULL) {
-                               ret = -ENOMEM;
-                               goto error;
-                       }
-                       if (pev->args[i].type) {
-                               tev->args[i].type = strdup(pev->args[i].type);
-                               if (tev->args[i].type == NULL) {
-                                       ret = -ENOMEM;
-                                       goto error;
-                               }
-                       }
+                       if (pev->args[i].name)
+                               tev->args[i].name =
+                                       strdup_or_goto(pev->args[i].name,
+                                                       nomem_out);
+
+                       tev->args[i].value = strdup_or_goto(pev->args[i].var,
+                                                           nomem_out);
+                       if (pev->args[i].type)
+                               tev->args[i].type =
+                                       strdup_or_goto(pev->args[i].type,
+                                                       nomem_out);
                }
        }
 
-       if (pev->uprobes)
-               return 1;
+out:
+       if (map && pev->uprobes) {
+               /* Only when using uprobe(exec) map needs to be released */
+               dso__delete(map->dso);
+               map__delete(map);
+       }
+       return ret;
 
-       /* Currently just checking function name from symbol map */
-       sym = __find_kernel_function_by_name(tev->point.symbol, NULL);
-       if (!sym) {
-               pr_warning("Kernel symbol \'%s\' not found.\n",
-                          tev->point.symbol);
-               ret = -ENOENT;
-               goto error;
-       } else if (tev->point.offset > sym->end - sym->start) {
-               pr_warning("Offset specified is greater than size of %s\n",
-                          tev->point.symbol);
-               ret = -ENOENT;
-               goto error;
+nomem_out:
+       ret = -ENOMEM;
+err_out:
+       clear_probe_trace_events(*tevs, num_matched_functions);
+       zfree(tevs);
+       goto out;
+}
+
+static int convert_to_probe_trace_events(struct perf_probe_event *pev,
+                                         struct probe_trace_event **tevs,
+                                         int max_tevs, const char *target)
+{
+       int ret;
 
+       if (pev->uprobes && !pev->group) {
+               /* Replace group name if not given */
+               ret = convert_exec_to_group(target, &pev->group);
+               if (ret != 0) {
+                       pr_warning("Failed to make a group name.\n");
+                       return ret;
+               }
        }
 
-       return 1;
-error:
-       clear_probe_trace_event(tev);
-       free(tev);
-       *tevs = NULL;
-       return ret;
+       /* Convert perf_probe_event with debuginfo */
+       ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, target);
+       if (ret != 0)
+               return ret;     /* Found in debuginfo or got an error */
+
+       return find_probe_trace_events_from_map(pev, tevs, max_tevs, target);
 }
 
 struct __event_package {
@@ -2135,12 +2334,7 @@ int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
        if (pkgs == NULL)
                return -ENOMEM;
 
-       if (!pevs->uprobes)
-               /* Init vmlinux path */
-               ret = init_vmlinux();
-       else
-               ret = init_user_exec();
-
+       ret = init_symbol_maps(pevs->uprobes);
        if (ret < 0) {
                free(pkgs);
                return ret;
@@ -2174,6 +2368,7 @@ end:
                zfree(&pkgs[i].tevs);
        }
        free(pkgs);
+       exit_symbol_maps();
 
        return ret;
 }
@@ -2323,159 +2518,51 @@ static struct strfilter *available_func_filter;
 static int filter_available_functions(struct map *map __maybe_unused,
                                      struct symbol *sym)
 {
-       if (sym->binding == STB_GLOBAL &&
+       if ((sym->binding == STB_GLOBAL || sym->binding == STB_LOCAL) &&
            strfilter__compare(available_func_filter, sym->name))
                return 0;
        return 1;
 }
 
-static int __show_available_funcs(struct map *map)
-{
-       if (map__load(map, filter_available_functions)) {
-               pr_err("Failed to load map.\n");
-               return -EINVAL;
-       }
-       if (!dso__sorted_by_name(map->dso, map->type))
-               dso__sort_by_name(map->dso, map->type);
-
-       dso__fprintf_symbols_by_name(map->dso, map->type, stdout);
-       return 0;
-}
-
-static int available_kernel_funcs(const char *module)
+int show_available_funcs(const char *target, struct strfilter *_filter,
+                                       bool user)
 {
        struct map *map;
        int ret;
 
-       ret = init_vmlinux();
+       ret = init_symbol_maps(user);
        if (ret < 0)
                return ret;
 
-       map = kernel_get_module_map(module);
+       /* Get a symbol map */
+       if (user)
+               map = dso__new_map(target);
+       else
+               map = kernel_get_module_map(target);
        if (!map) {
-               pr_err("Failed to find %s map.\n", (module) ? : "kernel");
+               pr_err("Failed to get a map for %s\n", (target) ? : "kernel");
                return -EINVAL;
        }
-       return __show_available_funcs(map);
-}
-
-static int available_user_funcs(const char *target)
-{
-       struct map *map;
-       int ret;
-
-       ret = init_user_exec();
-       if (ret < 0)
-               return ret;
-
-       map = dso__new_map(target);
-       ret = __show_available_funcs(map);
-       dso__delete(map->dso);
-       map__delete(map);
-       return ret;
-}
 
-int show_available_funcs(const char *target, struct strfilter *_filter,
-                                       bool user)
-{
-       setup_pager();
+       /* Load symbols with given filter */
        available_func_filter = _filter;
-
-       if (!user)
-               return available_kernel_funcs(target);
-
-       return available_user_funcs(target);
-}
-
-/*
- * uprobe_events only accepts address:
- * Convert function and any offset to address
- */
-static int convert_name_to_addr(struct perf_probe_event *pev, const char *exec)
-{
-       struct perf_probe_point *pp = &pev->point;
-       struct symbol *sym;
-       struct map *map = NULL;
-       char *function = NULL;
-       int ret = -EINVAL;
-       unsigned long long vaddr = 0;
-
-       if (!pp->function) {
-               pr_warning("No function specified for uprobes");
-               goto out;
-       }
-
-       function = strdup(pp->function);
-       if (!function) {
-               pr_warning("Failed to allocate memory by strdup.\n");
-               ret = -ENOMEM;
-               goto out;
-       }
-
-       map = dso__new_map(exec);
-       if (!map) {
-               pr_warning("Cannot find appropriate DSO for %s.\n", exec);
-               goto out;
-       }
-       available_func_filter = strfilter__new(function, NULL);
        if (map__load(map, filter_available_functions)) {
-               pr_err("Failed to load map.\n");
-               goto out;
-       }
-
-       sym = map__find_symbol_by_name(map, function, NULL);
-       if (!sym) {
-               pr_warning("Cannot find %s in DSO %s\n", function, exec);
-               goto out;
-       }
-
-       if (map->start > sym->start)
-               vaddr = map->start;
-       vaddr += sym->start + pp->offset + map->pgoff;
-       pp->offset = 0;
-
-       if (!pev->event) {
-               pev->event = function;
-               function = NULL;
-       }
-       if (!pev->group) {
-               char *ptr1, *ptr2, *exec_copy;
-
-               pev->group = zalloc(sizeof(char *) * 64);
-               exec_copy = strdup(exec);
-               if (!exec_copy) {
-                       ret = -ENOMEM;
-                       pr_warning("Failed to copy exec string.\n");
-                       goto out;
-               }
-
-               ptr1 = strdup(basename(exec_copy));
-               if (ptr1) {
-                       ptr2 = strpbrk(ptr1, "-._");
-                       if (ptr2)
-                               *ptr2 = '\0';
-                       e_snprintf(pev->group, 64, "%s_%s", PERFPROBE_GROUP,
-                                       ptr1);
-                       free(ptr1);
-               }
-               free(exec_copy);
-       }
-       free(pp->function);
-       pp->function = zalloc(sizeof(char *) * MAX_PROBE_ARGS);
-       if (!pp->function) {
-               ret = -ENOMEM;
-               pr_warning("Failed to allocate memory by zalloc.\n");
-               goto out;
+               pr_err("Failed to load symbols in %s\n", (target) ? : "kernel");
+               goto end;
        }
-       e_snprintf(pp->function, MAX_PROBE_ARGS, "0x%llx", vaddr);
-       ret = 0;
+       if (!dso__sorted_by_name(map->dso, map->type))
+               dso__sort_by_name(map->dso, map->type);
 
-out:
-       if (map) {
+       /* Show all (filtered) symbols */
+       setup_pager();
+       dso__fprintf_symbols_by_name(map->dso, map->type, stdout);
+end:
+       if (user) {
                dso__delete(map->dso);
                map__delete(map);
        }
-       if (function)
-               free(function);
+       exit_symbol_maps();
+
        return ret;
 }
+
index fcaf727..776c934 100644 (file)
@@ -2,6 +2,7 @@
 #define _PROBE_EVENT_H
 
 #include <stdbool.h>
+#include "intlist.h"
 #include "strlist.h"
 #include "strfilter.h"
 
@@ -76,13 +77,6 @@ struct perf_probe_event {
        struct perf_probe_arg   *args;  /* Arguments */
 };
 
-
-/* Line number container */
-struct line_node {
-       struct list_head        list;
-       int                     line;
-};
-
 /* Line range */
 struct line_range {
        char                    *file;          /* File name */
@@ -92,7 +86,7 @@ struct line_range {
        int                     offset;         /* Start line offset */
        char                    *path;          /* Real path name */
        char                    *comp_dir;      /* Compile directory */
-       struct list_head        line_list;      /* Visible lines */
+       struct intlist          *line_list;     /* Visible lines */
 };
 
 /* List of variables */
@@ -124,7 +118,7 @@ extern int parse_line_range_desc(const char *cmd, struct line_range *lr);
 extern void line_range__clear(struct line_range *lr);
 
 /* Initialize line range */
-extern void line_range__init(struct line_range *lr);
+extern int line_range__init(struct line_range *lr);
 
 /* Internal use: Return kernel/module path */
 extern const char *kernel_get_module_path(const char *module);
index 061edb1..df02386 100644 (file)
@@ -34,7 +34,9 @@
 
 #include <linux/bitops.h>
 #include "event.h"
+#include "dso.h"
 #include "debug.h"
+#include "intlist.h"
 #include "util.h"
 #include "symbol.h"
 #include "probe-finder.h"
 /* Kprobe tracer basic type is up to u64 */
 #define MAX_BASIC_TYPE_BITS    64
 
-/* Line number list operations */
-
-/* Add a line to line number list */
-static int line_list__add_line(struct list_head *head, int line)
-{
-       struct line_node *ln;
-       struct list_head *p;
-
-       /* Reverse search, because new line will be the last one */
-       list_for_each_entry_reverse(ln, head, list) {
-               if (ln->line < line) {
-                       p = &ln->list;
-                       goto found;
-               } else if (ln->line == line)    /* Already exist */
-                       return 1;
-       }
-       /* List is empty, or the smallest entry */
-       p = head;
-found:
-       pr_debug("line list: add a line %u\n", line);
-       ln = zalloc(sizeof(struct line_node));
-       if (ln == NULL)
-               return -ENOMEM;
-       ln->line = line;
-       INIT_LIST_HEAD(&ln->list);
-       list_add(&ln->list, p);
-       return 0;
-}
-
-/* Check if the line in line number list */
-static int line_list__has_line(struct list_head *head, int line)
-{
-       struct line_node *ln;
-
-       /* Reverse search, because new line will be the last one */
-       list_for_each_entry(ln, head, list)
-               if (ln->line == line)
-                       return 1;
-
-       return 0;
-}
-
-/* Init line number list */
-static void line_list__init(struct list_head *head)
-{
-       INIT_LIST_HEAD(head);
-}
-
-/* Free line number list */
-static void line_list__free(struct list_head *head)
-{
-       struct line_node *ln;
-       while (!list_empty(head)) {
-               ln = list_first_entry(head, struct line_node, list);
-               list_del(&ln->list);
-               free(ln);
-       }
-}
-
 /* Dwarf FL wrappers */
 static char *debuginfo_path;   /* Currently dummy */
 
@@ -147,80 +90,7 @@ error:
        return -ENOENT;
 }
 
-#if _ELFUTILS_PREREQ(0, 148)
-/* This method is buggy if elfutils is older than 0.148 */
-static int __linux_kernel_find_elf(Dwfl_Module *mod,
-                                  void **userdata,
-                                  const char *module_name,
-                                  Dwarf_Addr base,
-                                  char **file_name, Elf **elfp)
-{
-       int fd;
-       const char *path = kernel_get_module_path(module_name);
-
-       pr_debug2("Use file %s for %s\n", path, module_name);
-       if (path) {
-               fd = open(path, O_RDONLY);
-               if (fd >= 0) {
-                       *file_name = strdup(path);
-                       return fd;
-               }
-       }
-       /* If failed, try to call standard method */
-       return dwfl_linux_kernel_find_elf(mod, userdata, module_name, base,
-                                         file_name, elfp);
-}
-
-static const Dwfl_Callbacks kernel_callbacks = {
-       .find_debuginfo = dwfl_standard_find_debuginfo,
-       .debuginfo_path = &debuginfo_path,
-
-       .find_elf = __linux_kernel_find_elf,
-       .section_address = dwfl_linux_kernel_module_section_address,
-};
-
-/* Get a Dwarf from live kernel image */
-static int debuginfo__init_online_kernel_dwarf(struct debuginfo *dbg,
-                                              Dwarf_Addr addr)
-{
-       dbg->dwfl = dwfl_begin(&kernel_callbacks);
-       if (!dbg->dwfl)
-               return -EINVAL;
-
-       /* Load the kernel dwarves: Don't care the result here */
-       dwfl_linux_kernel_report_kernel(dbg->dwfl);
-       dwfl_linux_kernel_report_modules(dbg->dwfl);
-
-       dbg->dbg = dwfl_addrdwarf(dbg->dwfl, addr, &dbg->bias);
-       /* Here, check whether we could get a real dwarf */
-       if (!dbg->dbg) {
-               pr_debug("Failed to find kernel dwarf at %lx\n",
-                        (unsigned long)addr);
-               dwfl_end(dbg->dwfl);
-               memset(dbg, 0, sizeof(*dbg));
-               return -ENOENT;
-       }
-
-       return 0;
-}
-#else
-/* With older elfutils, this just support kernel module... */
-static int debuginfo__init_online_kernel_dwarf(struct debuginfo *dbg,
-                                              Dwarf_Addr addr __maybe_unused)
-{
-       const char *path = kernel_get_module_path("kernel");
-
-       if (!path) {
-               pr_err("Failed to find vmlinux path\n");
-               return -ENOENT;
-       }
-
-       pr_debug2("Use file %s for debuginfo\n", path);
-       return debuginfo__init_offline_dwarf(dbg, path);
-}
-#endif
-
-struct debuginfo *debuginfo__new(const char *path)
+static struct debuginfo *__debuginfo__new(const char *path)
 {
        struct debuginfo *dbg = zalloc(sizeof(*dbg));
        if (!dbg)
@@ -228,21 +98,44 @@ struct debuginfo *debuginfo__new(const char *path)
 
        if (debuginfo__init_offline_dwarf(dbg, path) < 0)
                zfree(&dbg);
-
+       if (dbg)
+               pr_debug("Open Debuginfo file: %s\n", path);
        return dbg;
 }
 
-struct debuginfo *debuginfo__new_online_kernel(unsigned long addr)
-{
-       struct debuginfo *dbg = zalloc(sizeof(*dbg));
+enum dso_binary_type distro_dwarf_types[] = {
+       DSO_BINARY_TYPE__FEDORA_DEBUGINFO,
+       DSO_BINARY_TYPE__UBUNTU_DEBUGINFO,
+       DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO,
+       DSO_BINARY_TYPE__BUILDID_DEBUGINFO,
+       DSO_BINARY_TYPE__NOT_FOUND,
+};
 
-       if (!dbg)
-               return NULL;
+struct debuginfo *debuginfo__new(const char *path)
+{
+       enum dso_binary_type *type;
+       char buf[PATH_MAX], nil = '\0';
+       struct dso *dso;
+       struct debuginfo *dinfo = NULL;
+
+       /* Try to open distro debuginfo files */
+       dso = dso__new(path);
+       if (!dso)
+               goto out;
 
-       if (debuginfo__init_online_kernel_dwarf(dbg, (Dwarf_Addr)addr) < 0)
-               zfree(&dbg);
+       for (type = distro_dwarf_types;
+            !dinfo && *type != DSO_BINARY_TYPE__NOT_FOUND;
+            type++) {
+               if (dso__read_binary_type_filename(dso, *type, &nil,
+                                                  buf, PATH_MAX) < 0)
+                       continue;
+               dinfo = __debuginfo__new(buf);
+       }
+       dso__delete(dso);
 
-       return dbg;
+out:
+       /* if failed to open all distro debuginfo, open given binary */
+       return dinfo ? : __debuginfo__new(path);
 }
 
 void debuginfo__delete(struct debuginfo *dbg)
@@ -880,7 +773,7 @@ static int find_probe_point_by_line(struct probe_finder *pf)
 }
 
 /* Find lines which match lazy pattern */
-static int find_lazy_match_lines(struct list_head *head,
+static int find_lazy_match_lines(struct intlist *list,
                                 const char *fname, const char *pat)
 {
        FILE *fp;
@@ -901,7 +794,7 @@ static int find_lazy_match_lines(struct list_head *head,
                        line[len - 1] = '\0';
 
                if (strlazymatch(line, pat)) {
-                       line_list__add_line(head, linenum);
+                       intlist__add(list, linenum);
                        count++;
                }
                linenum++;
@@ -924,7 +817,7 @@ static int probe_point_lazy_walker(const char *fname, int lineno,
        Dwarf_Die *sc_die, die_mem;
        int ret;
 
-       if (!line_list__has_line(&pf->lcache, lineno) ||
+       if (!intlist__has_entry(pf->lcache, lineno) ||
            strtailcmp(fname, pf->fname) != 0)
                return 0;
 
@@ -952,9 +845,9 @@ static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
 {
        int ret = 0;
 
-       if (list_empty(&pf->lcache)) {
+       if (intlist__empty(pf->lcache)) {
                /* Matching lazy line pattern */
-               ret = find_lazy_match_lines(&pf->lcache, pf->fname,
+               ret = find_lazy_match_lines(pf->lcache, pf->fname,
                                            pf->pev->point.lazy_line);
                if (ret <= 0)
                        return ret;
@@ -1096,7 +989,9 @@ static int debuginfo__find_probes(struct debuginfo *dbg,
 #endif
 
        off = 0;
-       line_list__init(&pf->lcache);
+       pf->lcache = intlist__new(NULL);
+       if (!pf->lcache)
+               return -ENOMEM;
 
        /* Fastpath: lookup by function name from .debug_pubnames section */
        if (pp->function) {
@@ -1149,7 +1044,8 @@ static int debuginfo__find_probes(struct debuginfo *dbg,
        }
 
 found:
-       line_list__free(&pf->lcache);
+       intlist__delete(pf->lcache);
+       pf->lcache = NULL;
 
        return ret;
 }
@@ -1537,7 +1433,7 @@ static int line_range_add_line(const char *src, unsigned int lineno,
                if (lr->path == NULL)
                        return -ENOMEM;
        }
-       return line_list__add_line(&lr->line_list, lineno);
+       return intlist__add(lr->line_list, lineno);
 }
 
 static int line_range_walk_cb(const char *fname, int lineno,
@@ -1565,7 +1461,7 @@ static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf)
 
        /* Update status */
        if (ret >= 0)
-               if (!list_empty(&lf->lr->line_list))
+               if (!intlist__empty(lf->lr->line_list))
                        ret = lf->found = 1;
                else
                        ret = 0;        /* Lines are not found */
index ffc33cd..92590b2 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <stdbool.h>
 #include "util.h"
+#include "intlist.h"
 #include "probe-event.h"
 
 #define MAX_PROBE_BUFFER       1024
@@ -29,8 +30,8 @@ struct debuginfo {
        Dwarf_Addr      bias;
 };
 
+/* This also tries to open distro debuginfo */
 extern struct debuginfo *debuginfo__new(const char *path);
-extern struct debuginfo *debuginfo__new_online_kernel(unsigned long addr);
 extern void debuginfo__delete(struct debuginfo *dbg);
 
 /* Find probe_trace_events specified by perf_probe_event from debuginfo */
@@ -66,7 +67,7 @@ struct probe_finder {
        const char              *fname;         /* Real file name */
        Dwarf_Die               cu_die;         /* Current CU */
        Dwarf_Die               sp_die;
-       struct list_head        lcache;         /* Line cache for lazy match */
+       struct intlist          *lcache;        /* Line cache for lazy match */
 
        /* For variable searching */
 #if _ELFUTILS_PREREQ(0, 142)
index 595bfc7..16a475a 100644 (file)
@@ -17,6 +17,6 @@ util/xyarray.c
 util/cgroup.c
 util/rblist.c
 util/strlist.c
-util/fs.c
+../lib/api/fs/fs.c
 util/trace-event.c
 ../../lib/rbtree.c
index 3737625..049e0a0 100644 (file)
@@ -2,7 +2,7 @@
 #include "evsel.h"
 #include "cpumap.h"
 #include "parse-events.h"
-#include "fs.h"
+#include <api/fs/fs.h>
 #include "util.h"
 
 typedef void (*setup_probe_fn_t)(struct perf_evsel *evsel);
index 5da6ce7..1d555d6 100644 (file)
@@ -702,11 +702,12 @@ static void regs_dump__printf(u64 mask, u64 *regs)
        }
 }
 
-static void regs_user__printf(struct perf_sample *sample, u64 mask)
+static void regs_user__printf(struct perf_sample *sample)
 {
        struct regs_dump *user_regs = &sample->user_regs;
 
        if (user_regs->regs) {
+               u64 mask = user_regs->mask;
                printf("... user regs: mask 0x%" PRIx64 "\n", mask);
                regs_dump__printf(mask, user_regs->regs);
        }
@@ -806,7 +807,7 @@ static void dump_sample(struct perf_evsel *evsel, union perf_event *event,
                branch_stack__printf(sample);
 
        if (sample_type & PERF_SAMPLE_REGS_USER)
-               regs_user__printf(sample, evsel->attr.sample_regs_user);
+               regs_user__printf(sample);
 
        if (sample_type & PERF_SAMPLE_STACK_USER)
                stack_user__printf(&sample->user_stack);
index a9d758a..46e2ede 100644 (file)
@@ -410,7 +410,7 @@ struct symbol *dso__find_symbol(struct dso *dso,
        return symbols__find(&dso->symbols[type], addr);
 }
 
-struct symbol *dso__first_symbol(struct dso *dso, enum map_type type)
+static struct symbol *dso__first_symbol(struct dso *dso, enum map_type type)
 {
        return symbols__first(&dso->symbols[type]);
 }
index fffe288..2553ae0 100644 (file)
@@ -79,6 +79,17 @@ struct symbol {
 void symbol__delete(struct symbol *sym);
 void symbols__delete(struct rb_root *symbols);
 
+/* symbols__for_each_entry - iterate over symbols (rb_root)
+ *
+ * @symbols: the rb_root of symbols
+ * @pos: the 'struct symbol *' to use as a loop cursor
+ * @nd: the 'struct rb_node *' to use as a temporary storage
+ */
+#define symbols__for_each_entry(symbols, pos, nd)                      \
+       for (nd = rb_first(symbols);                                    \
+            nd && (pos = rb_entry(nd, struct symbol, rb_node));        \
+            nd = rb_next(nd))
+
 static inline size_t symbol__size(const struct symbol *sym)
 {
        return sym->end - sym->start + 1;
@@ -223,7 +234,6 @@ struct symbol *dso__find_symbol(struct dso *dso, enum map_type type,
                                u64 addr);
 struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,
                                        const char *name);
-struct symbol *dso__first_symbol(struct dso *dso, enum map_type type);
 
 int filename__read_build_id(const char *filename, void *bf, size_t size);
 int sysfs__read_build_id(const char *filename, void *bf, size_t size);
index e0d6d07..c36636f 100644 (file)
@@ -126,6 +126,7 @@ void event_format__print(struct event_format *event,
        trace_seq_init(&s);
        pevent_event_info(&s, event, &record);
        trace_seq_do_printf(&s);
+       trace_seq_destroy(&s);
 }
 
 void parse_proc_kallsyms(struct pevent *pevent,
similarity index 92%
rename from tools/perf/util/unwind.c
rename to tools/perf/util/unwind-libunwind.c
index 742f23b..bd5768d 100644 (file)
@@ -86,7 +86,6 @@ struct unwind_info {
        struct perf_sample      *sample;
        struct machine          *machine;
        struct thread           *thread;
-       u64                     sample_uregs;
 };
 
 #define dw_read(ptr, type, end) ({     \
@@ -391,30 +390,13 @@ static int access_dso_mem(struct unwind_info *ui, unw_word_t addr,
        return !(size == sizeof(*data));
 }
 
-static int reg_value(unw_word_t *valp, struct regs_dump *regs, int id,
-                    u64 sample_regs)
-{
-       int i, idx = 0;
-
-       if (!(sample_regs & (1 << id)))
-               return -EINVAL;
-
-       for (i = 0; i < id; i++) {
-               if (sample_regs & (1 << i))
-                       idx++;
-       }
-
-       *valp = regs->regs[idx];
-       return 0;
-}
-
 static int access_mem(unw_addr_space_t __maybe_unused as,
                      unw_word_t addr, unw_word_t *valp,
                      int __write, void *arg)
 {
        struct unwind_info *ui = arg;
        struct stack_dump *stack = &ui->sample->user_stack;
-       unw_word_t start, end;
+       u64 start, end;
        int offset;
        int ret;
 
@@ -424,8 +406,7 @@ static int access_mem(unw_addr_space_t __maybe_unused as,
                return 0;
        }
 
-       ret = reg_value(&start, &ui->sample->user_regs, PERF_REG_SP,
-                       ui->sample_uregs);
+       ret = perf_reg_value(&start, &ui->sample->user_regs, PERF_REG_SP);
        if (ret)
                return ret;
 
@@ -438,8 +419,9 @@ static int access_mem(unw_addr_space_t __maybe_unused as,
        if (addr < start || addr + sizeof(unw_word_t) >= end) {
                ret = access_dso_mem(ui, addr, valp);
                if (ret) {
-                       pr_debug("unwind: access_mem %p not inside range %p-%p\n",
-                               (void *)addr, (void *)start, (void *)end);
+                       pr_debug("unwind: access_mem %p not inside range"
+                                " 0x%" PRIx64 "-0x%" PRIx64 "\n",
+                                (void *) addr, start, end);
                        *valp = 0;
                        return ret;
                }
@@ -448,8 +430,8 @@ static int access_mem(unw_addr_space_t __maybe_unused as,
 
        offset = addr - start;
        *valp  = *(unw_word_t *)&stack->data[offset];
-       pr_debug("unwind: access_mem addr %p, val %lx, offset %d\n",
-                (void *)addr, (unsigned long)*valp, offset);
+       pr_debug("unwind: access_mem addr %p val %lx, offset %d\n",
+                (void *) addr, (unsigned long)*valp, offset);
        return 0;
 }
 
@@ -459,6 +441,7 @@ static int access_reg(unw_addr_space_t __maybe_unused as,
 {
        struct unwind_info *ui = arg;
        int id, ret;
+       u64 val;
 
        /* Don't support write, I suspect we don't need it. */
        if (__write) {
@@ -471,16 +454,17 @@ static int access_reg(unw_addr_space_t __maybe_unused as,
                return 0;
        }
 
-       id = unwind__arch_reg_id(regnum);
+       id = libunwind__arch_reg_id(regnum);
        if (id < 0)
                return -EINVAL;
 
-       ret = reg_value(valp, &ui->sample->user_regs, id, ui->sample_uregs);
+       ret = perf_reg_value(&val, &ui->sample->user_regs, id);
        if (ret) {
                pr_err("unwind: can't read reg %d\n", regnum);
                return ret;
        }
 
+       *valp = (unw_word_t) val;
        pr_debug("unwind: reg %d, val %lx\n", regnum, (unsigned long)*valp);
        return 0;
 }
@@ -563,7 +547,7 @@ static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb,
                unw_word_t ip;
 
                unw_get_reg(&c, UNW_REG_IP, &ip);
-               ret = entry(ip, ui->thread, ui->machine, cb, arg);
+               ret = ip ? entry(ip, ui->thread, ui->machine, cb, arg) : 0;
        }
 
        unw_destroy_addr_space(addr_space);
@@ -572,13 +556,11 @@ static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb,
 
 int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
                        struct machine *machine, struct thread *thread,
-                       u64 sample_uregs, struct perf_sample *data,
-                       int max_stack)
+                       struct perf_sample *data, int max_stack)
 {
-       unw_word_t ip;
+       u64 ip;
        struct unwind_info ui = {
                .sample       = data,
-               .sample_uregs = sample_uregs,
                .thread       = thread,
                .machine      = machine,
        };
@@ -587,7 +569,7 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
        if (!data->user_regs.regs)
                return -EINVAL;
 
-       ret = reg_value(&ip, &data->user_regs, PERF_REG_IP, sample_uregs);
+       ret = perf_reg_value(&ip, &data->user_regs, PERF_REG_IP);
        if (ret)
                return ret;
 
@@ -595,5 +577,5 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
        if (ret)
                return -ENOMEM;
 
-       return get_entries(&ui, cb, arg, max_stack);
+       return --max_stack > 0 ? get_entries(&ui, cb, arg, max_stack) : 0;
 }
index d5966f4..b031316 100644 (file)
@@ -13,24 +13,25 @@ struct unwind_entry {
 
 typedef int (*unwind_entry_cb_t)(struct unwind_entry *entry, void *arg);
 
-#ifdef HAVE_LIBUNWIND_SUPPORT
+#ifdef HAVE_DWARF_UNWIND_SUPPORT
 int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
                        struct machine *machine,
                        struct thread *thread,
-                       u64 sample_uregs,
                        struct perf_sample *data, int max_stack);
-int unwind__arch_reg_id(int regnum);
+/* libunwind specific */
+#ifdef HAVE_LIBUNWIND_SUPPORT
+int libunwind__arch_reg_id(int regnum);
+#endif
 #else
 static inline int
 unwind__get_entries(unwind_entry_cb_t cb __maybe_unused,
                    void *arg __maybe_unused,
                    struct machine *machine __maybe_unused,
                    struct thread *thread __maybe_unused,
-                   u64 sample_uregs __maybe_unused,
                    struct perf_sample *data __maybe_unused,
                    int max_stack __maybe_unused)
 {
        return 0;
 }
-#endif /* HAVE_LIBUNWIND_SUPPORT */
+#endif /* HAVE_DWARF_UNWIND_SUPPORT */
 #endif /* __UNWIND_H */
index 42ad667..9f66549 100644 (file)
@@ -1,6 +1,6 @@
 #include "../perf.h"
 #include "util.h"
-#include "fs.h"
+#include <api/fs/fs.h>
 #include <sys/mman.h>
 #ifdef HAVE_BACKTRACE_SUPPORT
 #include <execinfo.h>