mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-12 16:11:04 +00:00
Merge branch 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull perf updates from Ingo Molnar: "The biggest changes are Intel Nehalem-EX PMU uncore support, uprobes updates/cleanups/fixes from Oleg and diverse tooling updates (mostly fixes) now that Arnaldo is back from vacation." * 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (40 commits) uprobes: __replace_page() needs munlock_vma_page() uprobes: Rename vma_address() and make it return "unsigned long" uprobes: Fix register_for_each_vma()->vma_address() check uprobes: Introduce vaddr_to_offset(vma, vaddr) uprobes: Teach build_probe_list() to consider the range uprobes: Remove insert_vm_struct()->uprobe_mmap() uprobes: Remove copy_vma()->uprobe_mmap() uprobes: Fix overflow in vma_address()/find_active_uprobe() uprobes: Suppress uprobe_munmap() from mmput() uprobes: Uprobe_mmap/munmap needs list_for_each_entry_safe() uprobes: Clean up and document write_opcode()->lock_page(old_page) uprobes: Kill write_opcode()->lock_page(new_page) uprobes: __replace_page() should not use page_address_in_vma() uprobes: Don't recheck vma/f_mapping in write_opcode() perf/x86: Fix missing struct before structure name perf/x86: Fix format definition of SNB-EP uncore QPI box perf/x86: Make bitfield unsigned perf/x86: Fix LLC-* and node-* events on Intel SandyBridge perf/x86: Add Intel Nehalem-EX uncore support perf/x86: Fix typo in format definition of uncore PCU filter ...
This commit is contained in:
commit
bca1a5c0ea
@ -234,7 +234,7 @@ extern struct perf_guest_switch_msr *perf_guest_get_msrs(int *nr);
|
||||
extern void perf_get_x86_pmu_capability(struct x86_pmu_capability *cap);
|
||||
extern void perf_check_microcode(void);
|
||||
#else
|
||||
static inline perf_guest_switch_msr *perf_guest_get_msrs(int *nr)
|
||||
static inline struct perf_guest_switch_msr *perf_guest_get_msrs(int *nr)
|
||||
{
|
||||
*nr = 0;
|
||||
return NULL;
|
||||
|
@ -374,7 +374,7 @@ struct x86_pmu {
|
||||
/*
|
||||
* Intel DebugStore bits
|
||||
*/
|
||||
int bts :1,
|
||||
unsigned int bts :1,
|
||||
bts_active :1,
|
||||
pebs :1,
|
||||
pebs_active :1,
|
||||
|
@ -138,6 +138,84 @@ static u64 intel_pmu_event_map(int hw_event)
|
||||
return intel_perfmon_event_map[hw_event];
|
||||
}
|
||||
|
||||
#define SNB_DMND_DATA_RD (1ULL << 0)
|
||||
#define SNB_DMND_RFO (1ULL << 1)
|
||||
#define SNB_DMND_IFETCH (1ULL << 2)
|
||||
#define SNB_DMND_WB (1ULL << 3)
|
||||
#define SNB_PF_DATA_RD (1ULL << 4)
|
||||
#define SNB_PF_RFO (1ULL << 5)
|
||||
#define SNB_PF_IFETCH (1ULL << 6)
|
||||
#define SNB_LLC_DATA_RD (1ULL << 7)
|
||||
#define SNB_LLC_RFO (1ULL << 8)
|
||||
#define SNB_LLC_IFETCH (1ULL << 9)
|
||||
#define SNB_BUS_LOCKS (1ULL << 10)
|
||||
#define SNB_STRM_ST (1ULL << 11)
|
||||
#define SNB_OTHER (1ULL << 15)
|
||||
#define SNB_RESP_ANY (1ULL << 16)
|
||||
#define SNB_NO_SUPP (1ULL << 17)
|
||||
#define SNB_LLC_HITM (1ULL << 18)
|
||||
#define SNB_LLC_HITE (1ULL << 19)
|
||||
#define SNB_LLC_HITS (1ULL << 20)
|
||||
#define SNB_LLC_HITF (1ULL << 21)
|
||||
#define SNB_LOCAL (1ULL << 22)
|
||||
#define SNB_REMOTE (0xffULL << 23)
|
||||
#define SNB_SNP_NONE (1ULL << 31)
|
||||
#define SNB_SNP_NOT_NEEDED (1ULL << 32)
|
||||
#define SNB_SNP_MISS (1ULL << 33)
|
||||
#define SNB_NO_FWD (1ULL << 34)
|
||||
#define SNB_SNP_FWD (1ULL << 35)
|
||||
#define SNB_HITM (1ULL << 36)
|
||||
#define SNB_NON_DRAM (1ULL << 37)
|
||||
|
||||
#define SNB_DMND_READ (SNB_DMND_DATA_RD|SNB_LLC_DATA_RD)
|
||||
#define SNB_DMND_WRITE (SNB_DMND_RFO|SNB_LLC_RFO)
|
||||
#define SNB_DMND_PREFETCH (SNB_PF_DATA_RD|SNB_PF_RFO)
|
||||
|
||||
#define SNB_SNP_ANY (SNB_SNP_NONE|SNB_SNP_NOT_NEEDED| \
|
||||
SNB_SNP_MISS|SNB_NO_FWD|SNB_SNP_FWD| \
|
||||
SNB_HITM)
|
||||
|
||||
#define SNB_DRAM_ANY (SNB_LOCAL|SNB_REMOTE|SNB_SNP_ANY)
|
||||
#define SNB_DRAM_REMOTE (SNB_REMOTE|SNB_SNP_ANY)
|
||||
|
||||
#define SNB_L3_ACCESS SNB_RESP_ANY
|
||||
#define SNB_L3_MISS (SNB_DRAM_ANY|SNB_NON_DRAM)
|
||||
|
||||
static __initconst const u64 snb_hw_cache_extra_regs
|
||||
[PERF_COUNT_HW_CACHE_MAX]
|
||||
[PERF_COUNT_HW_CACHE_OP_MAX]
|
||||
[PERF_COUNT_HW_CACHE_RESULT_MAX] =
|
||||
{
|
||||
[ C(LL ) ] = {
|
||||
[ C(OP_READ) ] = {
|
||||
[ C(RESULT_ACCESS) ] = SNB_DMND_READ|SNB_L3_ACCESS,
|
||||
[ C(RESULT_MISS) ] = SNB_DMND_READ|SNB_L3_MISS,
|
||||
},
|
||||
[ C(OP_WRITE) ] = {
|
||||
[ C(RESULT_ACCESS) ] = SNB_DMND_WRITE|SNB_L3_ACCESS,
|
||||
[ C(RESULT_MISS) ] = SNB_DMND_WRITE|SNB_L3_MISS,
|
||||
},
|
||||
[ C(OP_PREFETCH) ] = {
|
||||
[ C(RESULT_ACCESS) ] = SNB_DMND_PREFETCH|SNB_L3_ACCESS,
|
||||
[ C(RESULT_MISS) ] = SNB_DMND_PREFETCH|SNB_L3_MISS,
|
||||
},
|
||||
},
|
||||
[ C(NODE) ] = {
|
||||
[ C(OP_READ) ] = {
|
||||
[ C(RESULT_ACCESS) ] = SNB_DMND_READ|SNB_DRAM_ANY,
|
||||
[ C(RESULT_MISS) ] = SNB_DMND_READ|SNB_DRAM_REMOTE,
|
||||
},
|
||||
[ C(OP_WRITE) ] = {
|
||||
[ C(RESULT_ACCESS) ] = SNB_DMND_WRITE|SNB_DRAM_ANY,
|
||||
[ C(RESULT_MISS) ] = SNB_DMND_WRITE|SNB_DRAM_REMOTE,
|
||||
},
|
||||
[ C(OP_PREFETCH) ] = {
|
||||
[ C(RESULT_ACCESS) ] = SNB_DMND_PREFETCH|SNB_DRAM_ANY,
|
||||
[ C(RESULT_MISS) ] = SNB_DMND_PREFETCH|SNB_DRAM_REMOTE,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static __initconst const u64 snb_hw_cache_event_ids
|
||||
[PERF_COUNT_HW_CACHE_MAX]
|
||||
[PERF_COUNT_HW_CACHE_OP_MAX]
|
||||
@ -235,16 +313,16 @@ static __initconst const u64 snb_hw_cache_event_ids
|
||||
},
|
||||
[ C(NODE) ] = {
|
||||
[ C(OP_READ) ] = {
|
||||
[ C(RESULT_ACCESS) ] = -1,
|
||||
[ C(RESULT_MISS) ] = -1,
|
||||
[ C(RESULT_ACCESS) ] = 0x01b7,
|
||||
[ C(RESULT_MISS) ] = 0x01b7,
|
||||
},
|
||||
[ C(OP_WRITE) ] = {
|
||||
[ C(RESULT_ACCESS) ] = -1,
|
||||
[ C(RESULT_MISS) ] = -1,
|
||||
[ C(RESULT_ACCESS) ] = 0x01b7,
|
||||
[ C(RESULT_MISS) ] = 0x01b7,
|
||||
},
|
||||
[ C(OP_PREFETCH) ] = {
|
||||
[ C(RESULT_ACCESS) ] = -1,
|
||||
[ C(RESULT_MISS) ] = -1,
|
||||
[ C(RESULT_ACCESS) ] = 0x01b7,
|
||||
[ C(RESULT_MISS) ] = 0x01b7,
|
||||
},
|
||||
},
|
||||
|
||||
@ -1964,6 +2042,8 @@ __init int intel_pmu_init(void)
|
||||
case 58: /* IvyBridge */
|
||||
memcpy(hw_cache_event_ids, snb_hw_cache_event_ids,
|
||||
sizeof(hw_cache_event_ids));
|
||||
memcpy(hw_cache_extra_regs, snb_hw_cache_extra_regs,
|
||||
sizeof(hw_cache_extra_regs));
|
||||
|
||||
intel_pmu_lbr_init_snb();
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -5,8 +5,6 @@
|
||||
#include "perf_event.h"
|
||||
|
||||
#define UNCORE_PMU_NAME_LEN 32
|
||||
#define UNCORE_BOX_HASH_SIZE 8
|
||||
|
||||
#define UNCORE_PMU_HRTIMER_INTERVAL (60 * NSEC_PER_SEC)
|
||||
|
||||
#define UNCORE_FIXED_EVENT 0xff
|
||||
@ -115,6 +113,10 @@
|
||||
SNBEP_PCU_MSR_PMON_CTL_OCC_INVERT | \
|
||||
SNBEP_PCU_MSR_PMON_CTL_OCC_EDGE_DET)
|
||||
|
||||
#define SNBEP_QPI_PCI_PMON_RAW_EVENT_MASK \
|
||||
(SNBEP_PMON_RAW_EVENT_MASK | \
|
||||
SNBEP_PMON_CTL_EV_SEL_EXT)
|
||||
|
||||
/* SNB-EP pci control register */
|
||||
#define SNBEP_PCI_PMON_BOX_CTL 0xf4
|
||||
#define SNBEP_PCI_PMON_CTL0 0xd8
|
||||
@ -158,6 +160,193 @@
|
||||
#define SNBEP_PCU_MSR_CORE_C3_CTR 0x3fc
|
||||
#define SNBEP_PCU_MSR_CORE_C6_CTR 0x3fd
|
||||
|
||||
/* NHM-EX event control */
|
||||
#define NHMEX_PMON_CTL_EV_SEL_MASK 0x000000ff
|
||||
#define NHMEX_PMON_CTL_UMASK_MASK 0x0000ff00
|
||||
#define NHMEX_PMON_CTL_EN_BIT0 (1 << 0)
|
||||
#define NHMEX_PMON_CTL_EDGE_DET (1 << 18)
|
||||
#define NHMEX_PMON_CTL_PMI_EN (1 << 20)
|
||||
#define NHMEX_PMON_CTL_EN_BIT22 (1 << 22)
|
||||
#define NHMEX_PMON_CTL_INVERT (1 << 23)
|
||||
#define NHMEX_PMON_CTL_TRESH_MASK 0xff000000
|
||||
#define NHMEX_PMON_RAW_EVENT_MASK (NHMEX_PMON_CTL_EV_SEL_MASK | \
|
||||
NHMEX_PMON_CTL_UMASK_MASK | \
|
||||
NHMEX_PMON_CTL_EDGE_DET | \
|
||||
NHMEX_PMON_CTL_INVERT | \
|
||||
NHMEX_PMON_CTL_TRESH_MASK)
|
||||
|
||||
/* NHM-EX Ubox */
|
||||
#define NHMEX_U_MSR_PMON_GLOBAL_CTL 0xc00
|
||||
#define NHMEX_U_MSR_PMON_CTR 0xc11
|
||||
#define NHMEX_U_MSR_PMON_EV_SEL 0xc10
|
||||
|
||||
#define NHMEX_U_PMON_GLOBAL_EN (1 << 0)
|
||||
#define NHMEX_U_PMON_GLOBAL_PMI_CORE_SEL 0x0000001e
|
||||
#define NHMEX_U_PMON_GLOBAL_EN_ALL (1 << 28)
|
||||
#define NHMEX_U_PMON_GLOBAL_RST_ALL (1 << 29)
|
||||
#define NHMEX_U_PMON_GLOBAL_FRZ_ALL (1 << 31)
|
||||
|
||||
#define NHMEX_U_PMON_RAW_EVENT_MASK \
|
||||
(NHMEX_PMON_CTL_EV_SEL_MASK | \
|
||||
NHMEX_PMON_CTL_EDGE_DET)
|
||||
|
||||
/* NHM-EX Cbox */
|
||||
#define NHMEX_C0_MSR_PMON_GLOBAL_CTL 0xd00
|
||||
#define NHMEX_C0_MSR_PMON_CTR0 0xd11
|
||||
#define NHMEX_C0_MSR_PMON_EV_SEL0 0xd10
|
||||
#define NHMEX_C_MSR_OFFSET 0x20
|
||||
|
||||
/* NHM-EX Bbox */
|
||||
#define NHMEX_B0_MSR_PMON_GLOBAL_CTL 0xc20
|
||||
#define NHMEX_B0_MSR_PMON_CTR0 0xc31
|
||||
#define NHMEX_B0_MSR_PMON_CTL0 0xc30
|
||||
#define NHMEX_B_MSR_OFFSET 0x40
|
||||
#define NHMEX_B0_MSR_MATCH 0xe45
|
||||
#define NHMEX_B0_MSR_MASK 0xe46
|
||||
#define NHMEX_B1_MSR_MATCH 0xe4d
|
||||
#define NHMEX_B1_MSR_MASK 0xe4e
|
||||
|
||||
#define NHMEX_B_PMON_CTL_EN (1 << 0)
|
||||
#define NHMEX_B_PMON_CTL_EV_SEL_SHIFT 1
|
||||
#define NHMEX_B_PMON_CTL_EV_SEL_MASK \
|
||||
(0x1f << NHMEX_B_PMON_CTL_EV_SEL_SHIFT)
|
||||
#define NHMEX_B_PMON_CTR_SHIFT 6
|
||||
#define NHMEX_B_PMON_CTR_MASK \
|
||||
(0x3 << NHMEX_B_PMON_CTR_SHIFT)
|
||||
#define NHMEX_B_PMON_RAW_EVENT_MASK \
|
||||
(NHMEX_B_PMON_CTL_EV_SEL_MASK | \
|
||||
NHMEX_B_PMON_CTR_MASK)
|
||||
|
||||
/* NHM-EX Sbox */
|
||||
#define NHMEX_S0_MSR_PMON_GLOBAL_CTL 0xc40
|
||||
#define NHMEX_S0_MSR_PMON_CTR0 0xc51
|
||||
#define NHMEX_S0_MSR_PMON_CTL0 0xc50
|
||||
#define NHMEX_S_MSR_OFFSET 0x80
|
||||
#define NHMEX_S0_MSR_MM_CFG 0xe48
|
||||
#define NHMEX_S0_MSR_MATCH 0xe49
|
||||
#define NHMEX_S0_MSR_MASK 0xe4a
|
||||
#define NHMEX_S1_MSR_MM_CFG 0xe58
|
||||
#define NHMEX_S1_MSR_MATCH 0xe59
|
||||
#define NHMEX_S1_MSR_MASK 0xe5a
|
||||
|
||||
#define NHMEX_S_PMON_MM_CFG_EN (0x1ULL << 63)
|
||||
|
||||
/* NHM-EX Mbox */
|
||||
#define NHMEX_M0_MSR_GLOBAL_CTL 0xca0
|
||||
#define NHMEX_M0_MSR_PMU_DSP 0xca5
|
||||
#define NHMEX_M0_MSR_PMU_ISS 0xca6
|
||||
#define NHMEX_M0_MSR_PMU_MAP 0xca7
|
||||
#define NHMEX_M0_MSR_PMU_MSC_THR 0xca8
|
||||
#define NHMEX_M0_MSR_PMU_PGT 0xca9
|
||||
#define NHMEX_M0_MSR_PMU_PLD 0xcaa
|
||||
#define NHMEX_M0_MSR_PMU_ZDP_CTL_FVC 0xcab
|
||||
#define NHMEX_M0_MSR_PMU_CTL0 0xcb0
|
||||
#define NHMEX_M0_MSR_PMU_CNT0 0xcb1
|
||||
#define NHMEX_M_MSR_OFFSET 0x40
|
||||
#define NHMEX_M0_MSR_PMU_MM_CFG 0xe54
|
||||
#define NHMEX_M1_MSR_PMU_MM_CFG 0xe5c
|
||||
|
||||
#define NHMEX_M_PMON_MM_CFG_EN (1ULL << 63)
|
||||
#define NHMEX_M_PMON_ADDR_MATCH_MASK 0x3ffffffffULL
|
||||
#define NHMEX_M_PMON_ADDR_MASK_MASK 0x7ffffffULL
|
||||
#define NHMEX_M_PMON_ADDR_MASK_SHIFT 34
|
||||
|
||||
#define NHMEX_M_PMON_CTL_EN (1 << 0)
|
||||
#define NHMEX_M_PMON_CTL_PMI_EN (1 << 1)
|
||||
#define NHMEX_M_PMON_CTL_COUNT_MODE_SHIFT 2
|
||||
#define NHMEX_M_PMON_CTL_COUNT_MODE_MASK \
|
||||
(0x3 << NHMEX_M_PMON_CTL_COUNT_MODE_SHIFT)
|
||||
#define NHMEX_M_PMON_CTL_STORAGE_MODE_SHIFT 4
|
||||
#define NHMEX_M_PMON_CTL_STORAGE_MODE_MASK \
|
||||
(0x3 << NHMEX_M_PMON_CTL_STORAGE_MODE_SHIFT)
|
||||
#define NHMEX_M_PMON_CTL_WRAP_MODE (1 << 6)
|
||||
#define NHMEX_M_PMON_CTL_FLAG_MODE (1 << 7)
|
||||
#define NHMEX_M_PMON_CTL_INC_SEL_SHIFT 9
|
||||
#define NHMEX_M_PMON_CTL_INC_SEL_MASK \
|
||||
(0x1f << NHMEX_M_PMON_CTL_INC_SEL_SHIFT)
|
||||
#define NHMEX_M_PMON_CTL_SET_FLAG_SEL_SHIFT 19
|
||||
#define NHMEX_M_PMON_CTL_SET_FLAG_SEL_MASK \
|
||||
(0x7 << NHMEX_M_PMON_CTL_SET_FLAG_SEL_SHIFT)
|
||||
#define NHMEX_M_PMON_RAW_EVENT_MASK \
|
||||
(NHMEX_M_PMON_CTL_COUNT_MODE_MASK | \
|
||||
NHMEX_M_PMON_CTL_STORAGE_MODE_MASK | \
|
||||
NHMEX_M_PMON_CTL_WRAP_MODE | \
|
||||
NHMEX_M_PMON_CTL_FLAG_MODE | \
|
||||
NHMEX_M_PMON_CTL_INC_SEL_MASK | \
|
||||
NHMEX_M_PMON_CTL_SET_FLAG_SEL_MASK)
|
||||
|
||||
|
||||
#define NHMEX_M_PMON_ZDP_CTL_FVC_FVID_MASK 0x1f
|
||||
#define NHMEX_M_PMON_ZDP_CTL_FVC_BCMD_MASK (0x7 << 5)
|
||||
#define NHMEX_M_PMON_ZDP_CTL_FVC_RSP_MASK (0x7 << 8)
|
||||
#define NHMEX_M_PMON_ZDP_CTL_FVC_PBOX_INIT_ERR (1 << 23)
|
||||
#define NHMEX_M_PMON_ZDP_CTL_FVC_MASK \
|
||||
(NHMEX_M_PMON_ZDP_CTL_FVC_FVID_MASK | \
|
||||
NHMEX_M_PMON_ZDP_CTL_FVC_BCMD_MASK | \
|
||||
NHMEX_M_PMON_ZDP_CTL_FVC_RSP_MASK | \
|
||||
NHMEX_M_PMON_ZDP_CTL_FVC_PBOX_INIT_ERR)
|
||||
#define NHMEX_M_PMON_ZDP_CTL_FVC_EVENT_MASK(n) (0x7 << (11 + 3 * (n)))
|
||||
|
||||
/*
|
||||
* use the 9~13 bits to select event If the 7th bit is not set,
|
||||
* otherwise use the 19~21 bits to select event.
|
||||
*/
|
||||
#define MBOX_INC_SEL(x) ((x) << NHMEX_M_PMON_CTL_INC_SEL_SHIFT)
|
||||
#define MBOX_SET_FLAG_SEL(x) (((x) << NHMEX_M_PMON_CTL_SET_FLAG_SEL_SHIFT) | \
|
||||
NHMEX_M_PMON_CTL_FLAG_MODE)
|
||||
#define MBOX_INC_SEL_MASK (NHMEX_M_PMON_CTL_INC_SEL_MASK | \
|
||||
NHMEX_M_PMON_CTL_FLAG_MODE)
|
||||
#define MBOX_SET_FLAG_SEL_MASK (NHMEX_M_PMON_CTL_SET_FLAG_SEL_MASK | \
|
||||
NHMEX_M_PMON_CTL_FLAG_MODE)
|
||||
#define MBOX_INC_SEL_EXTAR_REG(c, r) \
|
||||
EVENT_EXTRA_REG(MBOX_INC_SEL(c), NHMEX_M0_MSR_PMU_##r, \
|
||||
MBOX_INC_SEL_MASK, (u64)-1, NHMEX_M_##r)
|
||||
#define MBOX_SET_FLAG_SEL_EXTRA_REG(c, r) \
|
||||
EVENT_EXTRA_REG(MBOX_SET_FLAG_SEL(c), NHMEX_M0_MSR_PMU_##r, \
|
||||
MBOX_SET_FLAG_SEL_MASK, \
|
||||
(u64)-1, NHMEX_M_##r)
|
||||
|
||||
/* NHM-EX Rbox */
|
||||
#define NHMEX_R_MSR_GLOBAL_CTL 0xe00
|
||||
#define NHMEX_R_MSR_PMON_CTL0 0xe10
|
||||
#define NHMEX_R_MSR_PMON_CNT0 0xe11
|
||||
#define NHMEX_R_MSR_OFFSET 0x20
|
||||
|
||||
#define NHMEX_R_MSR_PORTN_QLX_CFG(n) \
|
||||
((n) < 4 ? (0xe0c + (n)) : (0xe2c + (n) - 4))
|
||||
#define NHMEX_R_MSR_PORTN_IPERF_CFG0(n) (0xe04 + (n))
|
||||
#define NHMEX_R_MSR_PORTN_IPERF_CFG1(n) (0xe24 + (n))
|
||||
#define NHMEX_R_MSR_PORTN_XBR_OFFSET(n) \
|
||||
(((n) < 4 ? 0 : 0x10) + (n) * 4)
|
||||
#define NHMEX_R_MSR_PORTN_XBR_SET1_MM_CFG(n) \
|
||||
(0xe60 + NHMEX_R_MSR_PORTN_XBR_OFFSET(n))
|
||||
#define NHMEX_R_MSR_PORTN_XBR_SET1_MATCH(n) \
|
||||
(NHMEX_R_MSR_PORTN_XBR_SET1_MM_CFG(n) + 1)
|
||||
#define NHMEX_R_MSR_PORTN_XBR_SET1_MASK(n) \
|
||||
(NHMEX_R_MSR_PORTN_XBR_SET1_MM_CFG(n) + 2)
|
||||
#define NHMEX_R_MSR_PORTN_XBR_SET2_MM_CFG(n) \
|
||||
(0xe70 + NHMEX_R_MSR_PORTN_XBR_OFFSET(n))
|
||||
#define NHMEX_R_MSR_PORTN_XBR_SET2_MATCH(n) \
|
||||
(NHMEX_R_MSR_PORTN_XBR_SET2_MM_CFG(n) + 1)
|
||||
#define NHMEX_R_MSR_PORTN_XBR_SET2_MASK(n) \
|
||||
(NHMEX_R_MSR_PORTN_XBR_SET2_MM_CFG(n) + 2)
|
||||
|
||||
#define NHMEX_R_PMON_CTL_EN (1 << 0)
|
||||
#define NHMEX_R_PMON_CTL_EV_SEL_SHIFT 1
|
||||
#define NHMEX_R_PMON_CTL_EV_SEL_MASK \
|
||||
(0x1f << NHMEX_R_PMON_CTL_EV_SEL_SHIFT)
|
||||
#define NHMEX_R_PMON_CTL_PMI_EN (1 << 6)
|
||||
#define NHMEX_R_PMON_RAW_EVENT_MASK NHMEX_R_PMON_CTL_EV_SEL_MASK
|
||||
|
||||
/* NHM-EX Wbox */
|
||||
#define NHMEX_W_MSR_GLOBAL_CTL 0xc80
|
||||
#define NHMEX_W_MSR_PMON_CNT0 0xc90
|
||||
#define NHMEX_W_MSR_PMON_EVT_SEL0 0xc91
|
||||
#define NHMEX_W_MSR_PMON_FIXED_CTR 0x394
|
||||
#define NHMEX_W_MSR_PMON_FIXED_CTL 0x395
|
||||
|
||||
#define NHMEX_W_PMON_GLOBAL_FIXED_EN (1ULL << 31)
|
||||
|
||||
struct intel_uncore_ops;
|
||||
struct intel_uncore_pmu;
|
||||
struct intel_uncore_box;
|
||||
@ -178,6 +367,7 @@ struct intel_uncore_type {
|
||||
unsigned msr_offset;
|
||||
unsigned num_shared_regs:8;
|
||||
unsigned single_fixed:1;
|
||||
unsigned pair_ctr_ctl:1;
|
||||
struct event_constraint unconstrainted;
|
||||
struct event_constraint *constraints;
|
||||
struct intel_uncore_pmu *pmus;
|
||||
@ -213,7 +403,7 @@ struct intel_uncore_pmu {
|
||||
|
||||
struct intel_uncore_extra_reg {
|
||||
raw_spinlock_t lock;
|
||||
u64 config1;
|
||||
u64 config, config1, config2;
|
||||
atomic_t ref;
|
||||
};
|
||||
|
||||
@ -323,14 +513,16 @@ unsigned uncore_msr_fixed_ctr(struct intel_uncore_box *box)
|
||||
static inline
|
||||
unsigned uncore_msr_event_ctl(struct intel_uncore_box *box, int idx)
|
||||
{
|
||||
return idx + box->pmu->type->event_ctl +
|
||||
return box->pmu->type->event_ctl +
|
||||
(box->pmu->type->pair_ctr_ctl ? 2 * idx : idx) +
|
||||
box->pmu->type->msr_offset * box->pmu->pmu_idx;
|
||||
}
|
||||
|
||||
static inline
|
||||
unsigned uncore_msr_perf_ctr(struct intel_uncore_box *box, int idx)
|
||||
{
|
||||
return idx + box->pmu->type->perf_ctr +
|
||||
return box->pmu->type->perf_ctr +
|
||||
(box->pmu->type->pair_ctr_ctl ? 2 * idx : idx) +
|
||||
box->pmu->type->msr_offset * box->pmu->pmu_idx;
|
||||
}
|
||||
|
||||
@ -422,3 +614,8 @@ static inline void uncore_box_init(struct intel_uncore_box *box)
|
||||
box->pmu->type->ops->init_box(box);
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool uncore_box_is_fake(struct intel_uncore_box *box)
|
||||
{
|
||||
return (box->phys_id < 0);
|
||||
}
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include <linux/swap.h> /* try_to_free_swap */
|
||||
#include <linux/ptrace.h> /* user_enable_single_step */
|
||||
#include <linux/kdebug.h> /* notifier mechanism */
|
||||
#include "../../mm/internal.h" /* munlock_vma_page */
|
||||
|
||||
#include <linux/uprobes.h>
|
||||
|
||||
@ -112,14 +113,14 @@ static bool valid_vma(struct vm_area_struct *vma, bool is_register)
|
||||
return false;
|
||||
}
|
||||
|
||||
static loff_t vma_address(struct vm_area_struct *vma, loff_t offset)
|
||||
static unsigned long offset_to_vaddr(struct vm_area_struct *vma, loff_t offset)
|
||||
{
|
||||
loff_t vaddr;
|
||||
return vma->vm_start + offset - ((loff_t)vma->vm_pgoff << PAGE_SHIFT);
|
||||
}
|
||||
|
||||
vaddr = vma->vm_start + offset;
|
||||
vaddr -= vma->vm_pgoff << PAGE_SHIFT;
|
||||
|
||||
return vaddr;
|
||||
static loff_t vaddr_to_offset(struct vm_area_struct *vma, unsigned long vaddr)
|
||||
{
|
||||
return ((loff_t)vma->vm_pgoff << PAGE_SHIFT) + (vaddr - vma->vm_start);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -127,25 +128,27 @@ static loff_t vma_address(struct vm_area_struct *vma, loff_t offset)
|
||||
* based on replace_page in mm/ksm.c
|
||||
*
|
||||
* @vma: vma that holds the pte pointing to page
|
||||
* @addr: address the old @page is mapped at
|
||||
* @page: the cowed page we are replacing by kpage
|
||||
* @kpage: the modified page we replace page by
|
||||
*
|
||||
* Returns 0 on success, -EFAULT on failure.
|
||||
*/
|
||||
static int __replace_page(struct vm_area_struct *vma, struct page *page, struct page *kpage)
|
||||
static int __replace_page(struct vm_area_struct *vma, unsigned long addr,
|
||||
struct page *page, struct page *kpage)
|
||||
{
|
||||
struct mm_struct *mm = vma->vm_mm;
|
||||
unsigned long addr;
|
||||
spinlock_t *ptl;
|
||||
pte_t *ptep;
|
||||
int err;
|
||||
|
||||
addr = page_address_in_vma(page, vma);
|
||||
if (addr == -EFAULT)
|
||||
return -EFAULT;
|
||||
/* For try_to_free_swap() and munlock_vma_page() below */
|
||||
lock_page(page);
|
||||
|
||||
err = -EAGAIN;
|
||||
ptep = page_check_address(page, mm, addr, &ptl, 0);
|
||||
if (!ptep)
|
||||
return -EAGAIN;
|
||||
goto unlock;
|
||||
|
||||
get_page(kpage);
|
||||
page_add_new_anon_rmap(kpage, vma, addr);
|
||||
@ -162,10 +165,16 @@ static int __replace_page(struct vm_area_struct *vma, struct page *page, struct
|
||||
page_remove_rmap(page);
|
||||
if (!page_mapped(page))
|
||||
try_to_free_swap(page);
|
||||
put_page(page);
|
||||
pte_unmap_unlock(ptep, ptl);
|
||||
|
||||
return 0;
|
||||
if (vma->vm_flags & VM_LOCKED)
|
||||
munlock_vma_page(page);
|
||||
put_page(page);
|
||||
|
||||
err = 0;
|
||||
unlock:
|
||||
unlock_page(page);
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -206,45 +215,23 @@ static int write_opcode(struct arch_uprobe *auprobe, struct mm_struct *mm,
|
||||
unsigned long vaddr, uprobe_opcode_t opcode)
|
||||
{
|
||||
struct page *old_page, *new_page;
|
||||
struct address_space *mapping;
|
||||
void *vaddr_old, *vaddr_new;
|
||||
struct vm_area_struct *vma;
|
||||
struct uprobe *uprobe;
|
||||
int ret;
|
||||
|
||||
retry:
|
||||
/* Read the page with vaddr into memory */
|
||||
ret = get_user_pages(NULL, mm, vaddr, 1, 0, 0, &old_page, &vma);
|
||||
if (ret <= 0)
|
||||
return ret;
|
||||
|
||||
ret = -EINVAL;
|
||||
|
||||
/*
|
||||
* We are interested in text pages only. Our pages of interest
|
||||
* should be mapped for read and execute only. We desist from
|
||||
* adding probes in write mapped pages since the breakpoints
|
||||
* might end up in the file copy.
|
||||
*/
|
||||
if (!valid_vma(vma, is_swbp_insn(&opcode)))
|
||||
goto put_out;
|
||||
|
||||
uprobe = container_of(auprobe, struct uprobe, arch);
|
||||
mapping = uprobe->inode->i_mapping;
|
||||
if (mapping != vma->vm_file->f_mapping)
|
||||
goto put_out;
|
||||
|
||||
ret = -ENOMEM;
|
||||
new_page = alloc_page_vma(GFP_HIGHUSER_MOVABLE, vma, vaddr);
|
||||
if (!new_page)
|
||||
goto put_out;
|
||||
goto put_old;
|
||||
|
||||
__SetPageUptodate(new_page);
|
||||
|
||||
/*
|
||||
* lock page will serialize against do_wp_page()'s
|
||||
* PageAnon() handling
|
||||
*/
|
||||
lock_page(old_page);
|
||||
/* copy the page now that we've got it stable */
|
||||
vaddr_old = kmap_atomic(old_page);
|
||||
vaddr_new = kmap_atomic(new_page);
|
||||
@ -257,17 +244,13 @@ retry:
|
||||
|
||||
ret = anon_vma_prepare(vma);
|
||||
if (ret)
|
||||
goto unlock_out;
|
||||
goto put_new;
|
||||
|
||||
lock_page(new_page);
|
||||
ret = __replace_page(vma, old_page, new_page);
|
||||
unlock_page(new_page);
|
||||
ret = __replace_page(vma, vaddr, old_page, new_page);
|
||||
|
||||
unlock_out:
|
||||
unlock_page(old_page);
|
||||
put_new:
|
||||
page_cache_release(new_page);
|
||||
|
||||
put_out:
|
||||
put_old:
|
||||
put_page(old_page);
|
||||
|
||||
if (unlikely(ret == -EAGAIN))
|
||||
@ -791,7 +774,7 @@ build_map_info(struct address_space *mapping, loff_t offset, bool is_register)
|
||||
curr = info;
|
||||
|
||||
info->mm = vma->vm_mm;
|
||||
info->vaddr = vma_address(vma, offset);
|
||||
info->vaddr = offset_to_vaddr(vma, offset);
|
||||
}
|
||||
mutex_unlock(&mapping->i_mmap_mutex);
|
||||
|
||||
@ -839,12 +822,13 @@ static int register_for_each_vma(struct uprobe *uprobe, bool is_register)
|
||||
goto free;
|
||||
|
||||
down_write(&mm->mmap_sem);
|
||||
vma = find_vma(mm, (unsigned long)info->vaddr);
|
||||
if (!vma || !valid_vma(vma, is_register))
|
||||
vma = find_vma(mm, info->vaddr);
|
||||
if (!vma || !valid_vma(vma, is_register) ||
|
||||
vma->vm_file->f_mapping->host != uprobe->inode)
|
||||
goto unlock;
|
||||
|
||||
if (vma->vm_file->f_mapping->host != uprobe->inode ||
|
||||
vma_address(vma, uprobe->offset) != info->vaddr)
|
||||
if (vma->vm_start > info->vaddr ||
|
||||
vaddr_to_offset(vma, info->vaddr) != uprobe->offset)
|
||||
goto unlock;
|
||||
|
||||
if (is_register) {
|
||||
@ -960,59 +944,66 @@ void uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consume
|
||||
put_uprobe(uprobe);
|
||||
}
|
||||
|
||||
/*
|
||||
* Of all the nodes that correspond to the given inode, return the node
|
||||
* with the least offset.
|
||||
*/
|
||||
static struct rb_node *find_least_offset_node(struct inode *inode)
|
||||
static struct rb_node *
|
||||
find_node_in_range(struct inode *inode, loff_t min, loff_t max)
|
||||
{
|
||||
struct uprobe u = { .inode = inode, .offset = 0};
|
||||
struct rb_node *n = uprobes_tree.rb_node;
|
||||
struct rb_node *close_node = NULL;
|
||||
struct uprobe *uprobe;
|
||||
int match;
|
||||
|
||||
while (n) {
|
||||
uprobe = rb_entry(n, struct uprobe, rb_node);
|
||||
match = match_uprobe(&u, uprobe);
|
||||
struct uprobe *u = rb_entry(n, struct uprobe, rb_node);
|
||||
|
||||
if (uprobe->inode == inode)
|
||||
close_node = n;
|
||||
|
||||
if (!match)
|
||||
return close_node;
|
||||
|
||||
if (match < 0)
|
||||
if (inode < u->inode) {
|
||||
n = n->rb_left;
|
||||
else
|
||||
} else if (inode > u->inode) {
|
||||
n = n->rb_right;
|
||||
} else {
|
||||
if (max < u->offset)
|
||||
n = n->rb_left;
|
||||
else if (min > u->offset)
|
||||
n = n->rb_right;
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return close_node;
|
||||
return n;
|
||||
}
|
||||
|
||||
/*
|
||||
* For a given inode, build a list of probes that need to be inserted.
|
||||
* For a given range in vma, build a list of probes that need to be inserted.
|
||||
*/
|
||||
static void build_probe_list(struct inode *inode, struct list_head *head)
|
||||
static void build_probe_list(struct inode *inode,
|
||||
struct vm_area_struct *vma,
|
||||
unsigned long start, unsigned long end,
|
||||
struct list_head *head)
|
||||
{
|
||||
struct uprobe *uprobe;
|
||||
loff_t min, max;
|
||||
unsigned long flags;
|
||||
struct rb_node *n;
|
||||
struct rb_node *n, *t;
|
||||
struct uprobe *u;
|
||||
|
||||
INIT_LIST_HEAD(head);
|
||||
min = vaddr_to_offset(vma, start);
|
||||
max = min + (end - start) - 1;
|
||||
|
||||
spin_lock_irqsave(&uprobes_treelock, flags);
|
||||
|
||||
n = find_least_offset_node(inode);
|
||||
|
||||
for (; n; n = rb_next(n)) {
|
||||
uprobe = rb_entry(n, struct uprobe, rb_node);
|
||||
if (uprobe->inode != inode)
|
||||
break;
|
||||
|
||||
list_add(&uprobe->pending_list, head);
|
||||
atomic_inc(&uprobe->ref);
|
||||
n = find_node_in_range(inode, min, max);
|
||||
if (n) {
|
||||
for (t = n; t; t = rb_prev(t)) {
|
||||
u = rb_entry(t, struct uprobe, rb_node);
|
||||
if (u->inode != inode || u->offset < min)
|
||||
break;
|
||||
list_add(&u->pending_list, head);
|
||||
atomic_inc(&u->ref);
|
||||
}
|
||||
for (t = n; (t = rb_next(t)); ) {
|
||||
u = rb_entry(t, struct uprobe, rb_node);
|
||||
if (u->inode != inode || u->offset > max)
|
||||
break;
|
||||
list_add(&u->pending_list, head);
|
||||
atomic_inc(&u->ref);
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&uprobes_treelock, flags);
|
||||
}
|
||||
|
||||
@ -1031,7 +1022,7 @@ static void build_probe_list(struct inode *inode, struct list_head *head)
|
||||
int uprobe_mmap(struct vm_area_struct *vma)
|
||||
{
|
||||
struct list_head tmp_list;
|
||||
struct uprobe *uprobe;
|
||||
struct uprobe *uprobe, *u;
|
||||
struct inode *inode;
|
||||
int ret, count;
|
||||
|
||||
@ -1042,21 +1033,15 @@ int uprobe_mmap(struct vm_area_struct *vma)
|
||||
if (!inode)
|
||||
return 0;
|
||||
|
||||
INIT_LIST_HEAD(&tmp_list);
|
||||
mutex_lock(uprobes_mmap_hash(inode));
|
||||
build_probe_list(inode, &tmp_list);
|
||||
build_probe_list(inode, vma, vma->vm_start, vma->vm_end, &tmp_list);
|
||||
|
||||
ret = 0;
|
||||
count = 0;
|
||||
|
||||
list_for_each_entry(uprobe, &tmp_list, pending_list) {
|
||||
list_for_each_entry_safe(uprobe, u, &tmp_list, pending_list) {
|
||||
if (!ret) {
|
||||
loff_t vaddr = vma_address(vma, uprobe->offset);
|
||||
|
||||
if (vaddr < vma->vm_start || vaddr >= vma->vm_end) {
|
||||
put_uprobe(uprobe);
|
||||
continue;
|
||||
}
|
||||
unsigned long vaddr = offset_to_vaddr(vma, uprobe->offset);
|
||||
|
||||
ret = install_breakpoint(uprobe, vma->vm_mm, vma, vaddr);
|
||||
/*
|
||||
@ -1097,12 +1082,15 @@ int uprobe_mmap(struct vm_area_struct *vma)
|
||||
void uprobe_munmap(struct vm_area_struct *vma, unsigned long start, unsigned long end)
|
||||
{
|
||||
struct list_head tmp_list;
|
||||
struct uprobe *uprobe;
|
||||
struct uprobe *uprobe, *u;
|
||||
struct inode *inode;
|
||||
|
||||
if (!atomic_read(&uprobe_events) || !valid_vma(vma, false))
|
||||
return;
|
||||
|
||||
if (!atomic_read(&vma->vm_mm->mm_users)) /* called by mmput() ? */
|
||||
return;
|
||||
|
||||
if (!atomic_read(&vma->vm_mm->uprobes_state.count))
|
||||
return;
|
||||
|
||||
@ -1110,21 +1098,17 @@ void uprobe_munmap(struct vm_area_struct *vma, unsigned long start, unsigned lon
|
||||
if (!inode)
|
||||
return;
|
||||
|
||||
INIT_LIST_HEAD(&tmp_list);
|
||||
mutex_lock(uprobes_mmap_hash(inode));
|
||||
build_probe_list(inode, &tmp_list);
|
||||
build_probe_list(inode, vma, start, end, &tmp_list);
|
||||
|
||||
list_for_each_entry(uprobe, &tmp_list, pending_list) {
|
||||
loff_t vaddr = vma_address(vma, uprobe->offset);
|
||||
|
||||
if (vaddr >= start && vaddr < end) {
|
||||
/*
|
||||
* An unregister could have removed the probe before
|
||||
* unmap. So check before we decrement the count.
|
||||
*/
|
||||
if (is_swbp_at_addr(vma->vm_mm, vaddr) == 1)
|
||||
atomic_dec(&vma->vm_mm->uprobes_state.count);
|
||||
}
|
||||
list_for_each_entry_safe(uprobe, u, &tmp_list, pending_list) {
|
||||
unsigned long vaddr = offset_to_vaddr(vma, uprobe->offset);
|
||||
/*
|
||||
* An unregister could have removed the probe before
|
||||
* unmap. So check before we decrement the count.
|
||||
*/
|
||||
if (is_swbp_at_addr(vma->vm_mm, vaddr) == 1)
|
||||
atomic_dec(&vma->vm_mm->uprobes_state.count);
|
||||
put_uprobe(uprobe);
|
||||
}
|
||||
mutex_unlock(uprobes_mmap_hash(inode));
|
||||
@ -1463,12 +1447,9 @@ static struct uprobe *find_active_uprobe(unsigned long bp_vaddr, int *is_swbp)
|
||||
vma = find_vma(mm, bp_vaddr);
|
||||
if (vma && vma->vm_start <= bp_vaddr) {
|
||||
if (valid_vma(vma, false)) {
|
||||
struct inode *inode;
|
||||
loff_t offset;
|
||||
struct inode *inode = vma->vm_file->f_mapping->host;
|
||||
loff_t offset = vaddr_to_offset(vma, bp_vaddr);
|
||||
|
||||
inode = vma->vm_file->f_mapping->host;
|
||||
offset = bp_vaddr - vma->vm_start;
|
||||
offset += (vma->vm_pgoff << PAGE_SHIFT);
|
||||
uprobe = find_uprobe(inode, offset);
|
||||
}
|
||||
|
||||
|
@ -1910,12 +1910,12 @@ static inline void
|
||||
prepare_task_switch(struct rq *rq, struct task_struct *prev,
|
||||
struct task_struct *next)
|
||||
{
|
||||
trace_sched_switch(prev, next);
|
||||
sched_info_switch(prev, next);
|
||||
perf_event_task_sched_out(prev, next);
|
||||
fire_sched_out_preempt_notifiers(prev, next);
|
||||
prepare_lock_switch(rq, next);
|
||||
prepare_arch_switch(next);
|
||||
trace_sched_switch(prev, next);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2345,9 +2345,6 @@ int insert_vm_struct(struct mm_struct * mm, struct vm_area_struct * vma)
|
||||
security_vm_enough_memory_mm(mm, vma_pages(vma)))
|
||||
return -ENOMEM;
|
||||
|
||||
if (vma->vm_file && uprobe_mmap(vma))
|
||||
return -EINVAL;
|
||||
|
||||
vma_link(mm, vma, prev, rb_link, rb_parent);
|
||||
return 0;
|
||||
}
|
||||
@ -2418,9 +2415,6 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap,
|
||||
if (new_vma->vm_file) {
|
||||
get_file(new_vma->vm_file);
|
||||
|
||||
if (uprobe_mmap(new_vma))
|
||||
goto out_free_mempol;
|
||||
|
||||
if (vma->vm_flags & VM_EXECUTABLE)
|
||||
added_exe_file_vma(mm);
|
||||
}
|
||||
|
1
tools/lib/traceevent/.gitignore
vendored
Normal file
1
tools/lib/traceevent/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
TRACEEVENT-CFLAGS
|
@ -207,7 +207,7 @@ libtraceevent.so: $(PEVENT_LIB_OBJS)
|
||||
libtraceevent.a: $(PEVENT_LIB_OBJS)
|
||||
$(Q)$(do_build_static_lib)
|
||||
|
||||
$(PEVENT_LIB_OBJS): %.o: $(src)/%.c
|
||||
$(PEVENT_LIB_OBJS): %.o: $(src)/%.c TRACEEVENT-CFLAGS
|
||||
$(Q)$(do_fpic_compile)
|
||||
|
||||
define make_version.h
|
||||
@ -272,6 +272,16 @@ ifneq ($(dep_includes),)
|
||||
include $(dep_includes)
|
||||
endif
|
||||
|
||||
### Detect environment changes
|
||||
TRACK_CFLAGS = $(subst ','\'',$(CFLAGS)):$(ARCH):$(CROSS_COMPILE)
|
||||
|
||||
TRACEEVENT-CFLAGS: force
|
||||
@FLAGS='$(TRACK_CFLAGS)'; \
|
||||
if test x"$$FLAGS" != x"`cat TRACEEVENT-CFLAGS 2>/dev/null`" ; then \
|
||||
echo 1>&2 " * new build flags or cross compiler"; \
|
||||
echo "$$FLAGS" >TRACEEVENT-CFLAGS; \
|
||||
fi
|
||||
|
||||
tags: force
|
||||
$(RM) tags
|
||||
find . -name '*.[ch]' | xargs ctags --extra=+f --c-kinds=+px \
|
||||
@ -297,7 +307,7 @@ install: install_lib
|
||||
|
||||
clean:
|
||||
$(RM) *.o *~ $(TARGETS) *.a *.so $(VERSION_FILES) .*.d
|
||||
$(RM) tags TAGS
|
||||
$(RM) TRACEEVENT-CFLAGS tags TAGS
|
||||
|
||||
endif # skip-makefile
|
||||
|
||||
|
@ -354,6 +354,7 @@ LIB_OBJS += $(OUTPUT)util/usage.o
|
||||
LIB_OBJS += $(OUTPUT)util/wrapper.o
|
||||
LIB_OBJS += $(OUTPUT)util/sigchain.o
|
||||
LIB_OBJS += $(OUTPUT)util/symbol.o
|
||||
LIB_OBJS += $(OUTPUT)util/dso-test-data.o
|
||||
LIB_OBJS += $(OUTPUT)util/color.o
|
||||
LIB_OBJS += $(OUTPUT)util/pager.o
|
||||
LIB_OBJS += $(OUTPUT)util/header.o
|
||||
@ -803,6 +804,9 @@ $(OUTPUT)ui/browsers/map.o: ui/browsers/map.c $(OUTPUT)PERF-CFLAGS
|
||||
$(OUTPUT)util/rbtree.o: ../../lib/rbtree.c $(OUTPUT)PERF-CFLAGS
|
||||
$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
|
||||
|
||||
$(OUTPUT)util/parse-events.o: util/parse-events.c $(OUTPUT)PERF-CFLAGS
|
||||
$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -Wno-redundant-decls $<
|
||||
|
||||
$(OUTPUT)util/scripting-engines/trace-event-perl.o: util/scripting-engines/trace-event-perl.c $(OUTPUT)PERF-CFLAGS
|
||||
$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow $<
|
||||
|
||||
|
@ -1141,6 +1141,10 @@ static struct test {
|
||||
.desc = "Test perf pmu format parsing",
|
||||
.func = test__perf_pmu,
|
||||
},
|
||||
{
|
||||
.desc = "Test dso data interface",
|
||||
.func = dso__test_data,
|
||||
},
|
||||
{
|
||||
.func = NULL,
|
||||
},
|
||||
|
@ -125,7 +125,7 @@ static int perf_top__parse_source(struct perf_top *top, struct hist_entry *he)
|
||||
/*
|
||||
* We can't annotate with just /proc/kallsyms
|
||||
*/
|
||||
if (map->dso->symtab_type == SYMTAB__KALLSYMS) {
|
||||
if (map->dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS) {
|
||||
pr_err("Can't annotate %s: No vmlinux file was found in the "
|
||||
"path\n", sym->name);
|
||||
sleep(1);
|
||||
|
@ -978,8 +978,8 @@ static int hist_browser__dump(struct hist_browser *browser)
|
||||
fp = fopen(filename, "w");
|
||||
if (fp == NULL) {
|
||||
char bf[64];
|
||||
strerror_r(errno, bf, sizeof(bf));
|
||||
ui_helpline__fpush("Couldn't write to %s: %s", filename, bf);
|
||||
const char *err = strerror_r(errno, bf, sizeof(bf));
|
||||
ui_helpline__fpush("Couldn't write to %s: %s", filename, err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -426,7 +426,18 @@ int symbol__alloc_hist(struct symbol *sym)
|
||||
{
|
||||
struct annotation *notes = symbol__annotation(sym);
|
||||
const size_t size = symbol__size(sym);
|
||||
size_t sizeof_sym_hist = (sizeof(struct sym_hist) + size * sizeof(u64));
|
||||
size_t sizeof_sym_hist;
|
||||
|
||||
/* Check for overflow when calculating sizeof_sym_hist */
|
||||
if (size > (SIZE_MAX - sizeof(struct sym_hist)) / sizeof(u64))
|
||||
return -1;
|
||||
|
||||
sizeof_sym_hist = (sizeof(struct sym_hist) + size * sizeof(u64));
|
||||
|
||||
/* Check for overflow in zalloc argument */
|
||||
if (sizeof_sym_hist > (SIZE_MAX - sizeof(*notes->src))
|
||||
/ symbol_conf.nr_events)
|
||||
return -1;
|
||||
|
||||
notes->src = zalloc(sizeof(*notes->src) + symbol_conf.nr_events * sizeof_sym_hist);
|
||||
if (notes->src == NULL)
|
||||
@ -777,7 +788,7 @@ fallback:
|
||||
free_filename = false;
|
||||
}
|
||||
|
||||
if (dso->symtab_type == SYMTAB__KALLSYMS) {
|
||||
if (dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS) {
|
||||
char bf[BUILD_ID_SIZE * 2 + 16] = " with build id ";
|
||||
char *build_id_msg = NULL;
|
||||
|
||||
|
153
tools/perf/util/dso-test-data.c
Normal file
153
tools/perf/util/dso-test-data.c
Normal file
@ -0,0 +1,153 @@
|
||||
#include "util.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "symbol.h"
|
||||
|
||||
#define TEST_ASSERT_VAL(text, cond) \
|
||||
do { \
|
||||
if (!(cond)) { \
|
||||
pr_debug("FAILED %s:%d %s\n", __FILE__, __LINE__, text); \
|
||||
return -1; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static char *test_file(int size)
|
||||
{
|
||||
static char buf_templ[] = "/tmp/test-XXXXXX";
|
||||
char *templ = buf_templ;
|
||||
int fd, i;
|
||||
unsigned char *buf;
|
||||
|
||||
fd = mkostemp(templ, O_CREAT|O_WRONLY|O_TRUNC);
|
||||
|
||||
buf = malloc(size);
|
||||
if (!buf) {
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
buf[i] = (unsigned char) ((int) i % 10);
|
||||
|
||||
if (size != write(fd, buf, size))
|
||||
templ = NULL;
|
||||
|
||||
close(fd);
|
||||
return templ;
|
||||
}
|
||||
|
||||
#define TEST_FILE_SIZE (DSO__DATA_CACHE_SIZE * 20)
|
||||
|
||||
struct test_data_offset {
|
||||
off_t offset;
|
||||
u8 data[10];
|
||||
int size;
|
||||
};
|
||||
|
||||
struct test_data_offset offsets[] = {
|
||||
/* Fill first cache page. */
|
||||
{
|
||||
.offset = 10,
|
||||
.data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
|
||||
.size = 10,
|
||||
},
|
||||
/* Read first cache page. */
|
||||
{
|
||||
.offset = 10,
|
||||
.data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
|
||||
.size = 10,
|
||||
},
|
||||
/* Fill cache boundary pages. */
|
||||
{
|
||||
.offset = DSO__DATA_CACHE_SIZE - DSO__DATA_CACHE_SIZE % 10,
|
||||
.data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
|
||||
.size = 10,
|
||||
},
|
||||
/* Read cache boundary pages. */
|
||||
{
|
||||
.offset = DSO__DATA_CACHE_SIZE - DSO__DATA_CACHE_SIZE % 10,
|
||||
.data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
|
||||
.size = 10,
|
||||
},
|
||||
/* Fill final cache page. */
|
||||
{
|
||||
.offset = TEST_FILE_SIZE - 10,
|
||||
.data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
|
||||
.size = 10,
|
||||
},
|
||||
/* Read final cache page. */
|
||||
{
|
||||
.offset = TEST_FILE_SIZE - 10,
|
||||
.data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
|
||||
.size = 10,
|
||||
},
|
||||
/* Read final cache page. */
|
||||
{
|
||||
.offset = TEST_FILE_SIZE - 3,
|
||||
.data = { 7, 8, 9, 0, 0, 0, 0, 0, 0, 0 },
|
||||
.size = 3,
|
||||
},
|
||||
};
|
||||
|
||||
int dso__test_data(void)
|
||||
{
|
||||
struct machine machine;
|
||||
struct dso *dso;
|
||||
char *file = test_file(TEST_FILE_SIZE);
|
||||
size_t i;
|
||||
|
||||
TEST_ASSERT_VAL("No test file", file);
|
||||
|
||||
memset(&machine, 0, sizeof(machine));
|
||||
|
||||
dso = dso__new((const char *)file);
|
||||
|
||||
/* Basic 10 bytes tests. */
|
||||
for (i = 0; i < ARRAY_SIZE(offsets); i++) {
|
||||
struct test_data_offset *data = &offsets[i];
|
||||
ssize_t size;
|
||||
u8 buf[10];
|
||||
|
||||
memset(buf, 0, 10);
|
||||
size = dso__data_read_offset(dso, &machine, data->offset,
|
||||
buf, 10);
|
||||
|
||||
TEST_ASSERT_VAL("Wrong size", size == data->size);
|
||||
TEST_ASSERT_VAL("Wrong data", !memcmp(buf, data->data, 10));
|
||||
}
|
||||
|
||||
/* Read cross multiple cache pages. */
|
||||
{
|
||||
ssize_t size;
|
||||
int c;
|
||||
u8 *buf;
|
||||
|
||||
buf = malloc(TEST_FILE_SIZE);
|
||||
TEST_ASSERT_VAL("ENOMEM\n", buf);
|
||||
|
||||
/* First iteration to fill caches, second one to read them. */
|
||||
for (c = 0; c < 2; c++) {
|
||||
memset(buf, 0, TEST_FILE_SIZE);
|
||||
size = dso__data_read_offset(dso, &machine, 10,
|
||||
buf, TEST_FILE_SIZE);
|
||||
|
||||
TEST_ASSERT_VAL("Wrong size",
|
||||
size == (TEST_FILE_SIZE - 10));
|
||||
|
||||
for (i = 0; i < (size_t)size; i++)
|
||||
TEST_ASSERT_VAL("Wrong data",
|
||||
buf[i] == (i % 10));
|
||||
}
|
||||
|
||||
free(buf);
|
||||
}
|
||||
|
||||
dso__delete(dso);
|
||||
unlink(file);
|
||||
return 0;
|
||||
}
|
@ -214,7 +214,7 @@ int perf_evlist__add_tracepoints(struct perf_evlist *evlist,
|
||||
attrs[i].type = PERF_TYPE_TRACEPOINT;
|
||||
attrs[i].config = err;
|
||||
attrs[i].sample_type = (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME |
|
||||
PERF_SAMPLE_CPU);
|
||||
PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD);
|
||||
attrs[i].sample_period = 1;
|
||||
}
|
||||
|
||||
|
@ -1212,6 +1212,12 @@ static void print_event_desc(struct perf_header *ph, int fd, FILE *fp)
|
||||
attr.exclude_user,
|
||||
attr.exclude_kernel);
|
||||
|
||||
fprintf(fp, ", excl_host = %d, excl_guest = %d",
|
||||
attr.exclude_host,
|
||||
attr.exclude_guest);
|
||||
|
||||
fprintf(fp, ", precise_ip = %d", attr.precise_ip);
|
||||
|
||||
if (nr)
|
||||
fprintf(fp, ", id = {");
|
||||
|
||||
|
@ -708,7 +708,7 @@ static size_t callchain__fprintf_graph(FILE *fp, struct rb_root *root,
|
||||
bool printed = false;
|
||||
struct rb_node *node;
|
||||
int i = 0;
|
||||
int ret;
|
||||
int ret = 0;
|
||||
|
||||
/*
|
||||
* If have one single callchain root, don't bother printing
|
||||
@ -747,8 +747,11 @@ static size_t callchain__fprintf_graph(FILE *fp, struct rb_root *root,
|
||||
root = &cnode->rb_root;
|
||||
}
|
||||
|
||||
return __callchain__fprintf_graph(fp, root, total_samples,
|
||||
ret += __callchain__fprintf_graph(fp, root, total_samples,
|
||||
1, 1, left_margin);
|
||||
ret += fprintf(fp, "\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static size_t __callchain__fprintf_flat(FILE *fp,
|
||||
|
@ -7,6 +7,8 @@
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include "map.h"
|
||||
#include "thread.h"
|
||||
#include "strlist.h"
|
||||
|
||||
const char *map_type__name[MAP__NR_TYPES] = {
|
||||
[MAP__FUNCTION] = "Functions",
|
||||
@ -585,7 +587,21 @@ int machine__init(struct machine *self, const char *root_dir, pid_t pid)
|
||||
self->kmaps.machine = self;
|
||||
self->pid = pid;
|
||||
self->root_dir = strdup(root_dir);
|
||||
return self->root_dir == NULL ? -ENOMEM : 0;
|
||||
if (self->root_dir == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
if (pid != HOST_KERNEL_ID) {
|
||||
struct thread *thread = machine__findnew_thread(self, pid);
|
||||
char comm[64];
|
||||
|
||||
if (thread == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
snprintf(comm, sizeof(comm), "[guest/%d]", pid);
|
||||
thread__set_comm(thread, comm);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dsos__delete(struct list_head *self)
|
||||
@ -680,7 +696,15 @@ struct machine *machines__findnew(struct rb_root *self, pid_t pid)
|
||||
(symbol_conf.guestmount)) {
|
||||
sprintf(path, "%s/%d", symbol_conf.guestmount, pid);
|
||||
if (access(path, R_OK)) {
|
||||
pr_err("Can't access file %s\n", path);
|
||||
static struct strlist *seen;
|
||||
|
||||
if (!seen)
|
||||
seen = strlist__new(true, NULL);
|
||||
|
||||
if (!strlist__has_entry(seen, path)) {
|
||||
pr_err("Can't access file %s\n", path);
|
||||
strlist__add(seen, path);
|
||||
}
|
||||
machine = NULL;
|
||||
goto out;
|
||||
}
|
||||
@ -714,3 +738,16 @@ char *machine__mmap_name(struct machine *self, char *bf, size_t size)
|
||||
|
||||
return bf;
|
||||
}
|
||||
|
||||
void machines__set_id_hdr_size(struct rb_root *machines, u16 id_hdr_size)
|
||||
{
|
||||
struct rb_node *node;
|
||||
struct machine *machine;
|
||||
|
||||
for (node = rb_first(machines); node; node = rb_next(node)) {
|
||||
machine = rb_entry(node, struct machine, rb_node);
|
||||
machine->id_hdr_size = id_hdr_size;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -151,6 +151,7 @@ struct machine *machines__add(struct rb_root *self, pid_t pid,
|
||||
struct machine *machines__find_host(struct rb_root *self);
|
||||
struct machine *machines__find(struct rb_root *self, pid_t pid);
|
||||
struct machine *machines__findnew(struct rb_root *self, pid_t pid);
|
||||
void machines__set_id_hdr_size(struct rb_root *self, u16 id_hdr_size);
|
||||
char *machine__mmap_name(struct machine *self, char *bf, size_t size);
|
||||
int machine__init(struct machine *self, const char *root_dir, pid_t pid);
|
||||
void machine__exit(struct machine *self);
|
||||
|
@ -377,6 +377,7 @@ static int add_tracepoint(struct list_head **list, int *idx,
|
||||
attr.sample_type |= PERF_SAMPLE_RAW;
|
||||
attr.sample_type |= PERF_SAMPLE_TIME;
|
||||
attr.sample_type |= PERF_SAMPLE_CPU;
|
||||
attr.sample_type |= PERF_SAMPLE_PERIOD;
|
||||
attr.sample_period = 1;
|
||||
|
||||
snprintf(name, MAX_NAME_LEN, "%s:%s", sys_name, evt_name);
|
||||
@ -489,6 +490,7 @@ int parse_events_add_breakpoint(struct list_head **list, int *idx,
|
||||
attr.bp_len = HW_BREAKPOINT_LEN_4;
|
||||
|
||||
attr.type = PERF_TYPE_BREAKPOINT;
|
||||
attr.sample_period = 1;
|
||||
|
||||
return add_event(list, idx, &attr, NULL);
|
||||
}
|
||||
|
@ -87,6 +87,7 @@ void perf_session__update_sample_type(struct perf_session *self)
|
||||
self->sample_id_all = perf_evlist__sample_id_all(self->evlist);
|
||||
self->id_hdr_size = perf_evlist__id_hdr_size(self->evlist);
|
||||
self->host_machine.id_hdr_size = self->id_hdr_size;
|
||||
machines__set_id_hdr_size(&self->machines, self->id_hdr_size);
|
||||
}
|
||||
|
||||
int perf_session__create_kernel_maps(struct perf_session *self)
|
||||
@ -918,7 +919,9 @@ static struct machine *
|
||||
{
|
||||
const u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
|
||||
|
||||
if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL && perf_guest) {
|
||||
if (perf_guest &&
|
||||
((cpumode == PERF_RECORD_MISC_GUEST_KERNEL) ||
|
||||
(cpumode == PERF_RECORD_MISC_GUEST_USER))) {
|
||||
u32 pid;
|
||||
|
||||
if (event->header.type == PERF_RECORD_MMAP)
|
||||
|
@ -29,6 +29,7 @@
|
||||
#define NT_GNU_BUILD_ID 3
|
||||
#endif
|
||||
|
||||
static void dso_cache__free(struct rb_root *root);
|
||||
static bool dso__build_id_equal(const struct dso *dso, u8 *build_id);
|
||||
static int elf_read_build_id(Elf *elf, void *bf, size_t size);
|
||||
static void dsos__add(struct list_head *head, struct dso *dso);
|
||||
@ -48,6 +49,31 @@ struct symbol_conf symbol_conf = {
|
||||
.symfs = "",
|
||||
};
|
||||
|
||||
static enum dso_binary_type binary_type_symtab[] = {
|
||||
DSO_BINARY_TYPE__KALLSYMS,
|
||||
DSO_BINARY_TYPE__GUEST_KALLSYMS,
|
||||
DSO_BINARY_TYPE__JAVA_JIT,
|
||||
DSO_BINARY_TYPE__DEBUGLINK,
|
||||
DSO_BINARY_TYPE__BUILD_ID_CACHE,
|
||||
DSO_BINARY_TYPE__FEDORA_DEBUGINFO,
|
||||
DSO_BINARY_TYPE__UBUNTU_DEBUGINFO,
|
||||
DSO_BINARY_TYPE__BUILDID_DEBUGINFO,
|
||||
DSO_BINARY_TYPE__SYSTEM_PATH_DSO,
|
||||
DSO_BINARY_TYPE__GUEST_KMODULE,
|
||||
DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE,
|
||||
DSO_BINARY_TYPE__NOT_FOUND,
|
||||
};
|
||||
|
||||
#define DSO_BINARY_TYPE__SYMTAB_CNT sizeof(binary_type_symtab)
|
||||
|
||||
static enum dso_binary_type binary_type_data[] = {
|
||||
DSO_BINARY_TYPE__BUILD_ID_CACHE,
|
||||
DSO_BINARY_TYPE__SYSTEM_PATH_DSO,
|
||||
DSO_BINARY_TYPE__NOT_FOUND,
|
||||
};
|
||||
|
||||
#define DSO_BINARY_TYPE__DATA_CNT sizeof(binary_type_data)
|
||||
|
||||
int dso__name_len(const struct dso *dso)
|
||||
{
|
||||
if (!dso)
|
||||
@ -318,7 +344,9 @@ struct dso *dso__new(const char *name)
|
||||
dso__set_short_name(dso, dso->name);
|
||||
for (i = 0; i < MAP__NR_TYPES; ++i)
|
||||
dso->symbols[i] = dso->symbol_names[i] = RB_ROOT;
|
||||
dso->symtab_type = SYMTAB__NOT_FOUND;
|
||||
dso->cache = RB_ROOT;
|
||||
dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND;
|
||||
dso->data_type = DSO_BINARY_TYPE__NOT_FOUND;
|
||||
dso->loaded = 0;
|
||||
dso->sorted_by_name = 0;
|
||||
dso->has_build_id = 0;
|
||||
@ -352,6 +380,7 @@ void dso__delete(struct dso *dso)
|
||||
free((char *)dso->short_name);
|
||||
if (dso->lname_alloc)
|
||||
free(dso->long_name);
|
||||
dso_cache__free(&dso->cache);
|
||||
free(dso);
|
||||
}
|
||||
|
||||
@ -806,9 +835,9 @@ int dso__load_kallsyms(struct dso *dso, const char *filename,
|
||||
symbols__fixup_end(&dso->symbols[map->type]);
|
||||
|
||||
if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
|
||||
dso->symtab_type = SYMTAB__GUEST_KALLSYMS;
|
||||
dso->symtab_type = DSO_BINARY_TYPE__GUEST_KALLSYMS;
|
||||
else
|
||||
dso->symtab_type = SYMTAB__KALLSYMS;
|
||||
dso->symtab_type = DSO_BINARY_TYPE__KALLSYMS;
|
||||
|
||||
return dso__split_kallsyms(dso, map, filter);
|
||||
}
|
||||
@ -1660,32 +1689,110 @@ out:
|
||||
char dso__symtab_origin(const struct dso *dso)
|
||||
{
|
||||
static const char origin[] = {
|
||||
[SYMTAB__KALLSYMS] = 'k',
|
||||
[SYMTAB__JAVA_JIT] = 'j',
|
||||
[SYMTAB__DEBUGLINK] = 'l',
|
||||
[SYMTAB__BUILD_ID_CACHE] = 'B',
|
||||
[SYMTAB__FEDORA_DEBUGINFO] = 'f',
|
||||
[SYMTAB__UBUNTU_DEBUGINFO] = 'u',
|
||||
[SYMTAB__BUILDID_DEBUGINFO] = 'b',
|
||||
[SYMTAB__SYSTEM_PATH_DSO] = 'd',
|
||||
[SYMTAB__SYSTEM_PATH_KMODULE] = 'K',
|
||||
[SYMTAB__GUEST_KALLSYMS] = 'g',
|
||||
[SYMTAB__GUEST_KMODULE] = 'G',
|
||||
[DSO_BINARY_TYPE__KALLSYMS] = 'k',
|
||||
[DSO_BINARY_TYPE__JAVA_JIT] = 'j',
|
||||
[DSO_BINARY_TYPE__DEBUGLINK] = 'l',
|
||||
[DSO_BINARY_TYPE__BUILD_ID_CACHE] = 'B',
|
||||
[DSO_BINARY_TYPE__FEDORA_DEBUGINFO] = 'f',
|
||||
[DSO_BINARY_TYPE__UBUNTU_DEBUGINFO] = 'u',
|
||||
[DSO_BINARY_TYPE__BUILDID_DEBUGINFO] = 'b',
|
||||
[DSO_BINARY_TYPE__SYSTEM_PATH_DSO] = 'd',
|
||||
[DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE] = 'K',
|
||||
[DSO_BINARY_TYPE__GUEST_KALLSYMS] = 'g',
|
||||
[DSO_BINARY_TYPE__GUEST_KMODULE] = 'G',
|
||||
};
|
||||
|
||||
if (dso == NULL || dso->symtab_type == SYMTAB__NOT_FOUND)
|
||||
if (dso == NULL || dso->symtab_type == DSO_BINARY_TYPE__NOT_FOUND)
|
||||
return '!';
|
||||
return origin[dso->symtab_type];
|
||||
}
|
||||
|
||||
int dso__binary_type_file(struct dso *dso, enum dso_binary_type type,
|
||||
char *root_dir, char *file, size_t size)
|
||||
{
|
||||
char build_id_hex[BUILD_ID_SIZE * 2 + 1];
|
||||
int ret = 0;
|
||||
|
||||
switch (type) {
|
||||
case DSO_BINARY_TYPE__DEBUGLINK: {
|
||||
char *debuglink;
|
||||
|
||||
strncpy(file, dso->long_name, size);
|
||||
debuglink = file + dso->long_name_len;
|
||||
while (debuglink != file && *debuglink != '/')
|
||||
debuglink--;
|
||||
if (*debuglink == '/')
|
||||
debuglink++;
|
||||
filename__read_debuglink(dso->long_name, debuglink,
|
||||
size - (debuglink - file));
|
||||
}
|
||||
break;
|
||||
case DSO_BINARY_TYPE__BUILD_ID_CACHE:
|
||||
/* skip the locally configured cache if a symfs is given */
|
||||
if (symbol_conf.symfs[0] ||
|
||||
(dso__build_id_filename(dso, file, size) == NULL))
|
||||
ret = -1;
|
||||
break;
|
||||
|
||||
case DSO_BINARY_TYPE__FEDORA_DEBUGINFO:
|
||||
snprintf(file, size, "%s/usr/lib/debug%s.debug",
|
||||
symbol_conf.symfs, dso->long_name);
|
||||
break;
|
||||
|
||||
case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO:
|
||||
snprintf(file, size, "%s/usr/lib/debug%s",
|
||||
symbol_conf.symfs, dso->long_name);
|
||||
break;
|
||||
|
||||
case DSO_BINARY_TYPE__BUILDID_DEBUGINFO:
|
||||
if (!dso->has_build_id) {
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
build_id__sprintf(dso->build_id,
|
||||
sizeof(dso->build_id),
|
||||
build_id_hex);
|
||||
snprintf(file, size,
|
||||
"%s/usr/lib/debug/.build-id/%.2s/%s.debug",
|
||||
symbol_conf.symfs, build_id_hex, build_id_hex + 2);
|
||||
break;
|
||||
|
||||
case DSO_BINARY_TYPE__SYSTEM_PATH_DSO:
|
||||
snprintf(file, size, "%s%s",
|
||||
symbol_conf.symfs, dso->long_name);
|
||||
break;
|
||||
|
||||
case DSO_BINARY_TYPE__GUEST_KMODULE:
|
||||
snprintf(file, size, "%s%s%s", symbol_conf.symfs,
|
||||
root_dir, dso->long_name);
|
||||
break;
|
||||
|
||||
case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE:
|
||||
snprintf(file, size, "%s%s", symbol_conf.symfs,
|
||||
dso->long_name);
|
||||
break;
|
||||
|
||||
default:
|
||||
case DSO_BINARY_TYPE__KALLSYMS:
|
||||
case DSO_BINARY_TYPE__GUEST_KALLSYMS:
|
||||
case DSO_BINARY_TYPE__JAVA_JIT:
|
||||
case DSO_BINARY_TYPE__NOT_FOUND:
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
|
||||
{
|
||||
int size = PATH_MAX;
|
||||
char *name;
|
||||
int ret = -1;
|
||||
int fd;
|
||||
u_int i;
|
||||
struct machine *machine;
|
||||
const char *root_dir;
|
||||
char *root_dir = (char *) "";
|
||||
int want_symtab;
|
||||
|
||||
dso__set_loaded(dso, map->type);
|
||||
@ -1700,7 +1807,7 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
|
||||
else
|
||||
machine = NULL;
|
||||
|
||||
name = malloc(size);
|
||||
name = malloc(PATH_MAX);
|
||||
if (!name)
|
||||
return -1;
|
||||
|
||||
@ -1719,81 +1826,27 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
|
||||
}
|
||||
|
||||
ret = dso__load_perf_map(dso, map, filter);
|
||||
dso->symtab_type = ret > 0 ? SYMTAB__JAVA_JIT :
|
||||
SYMTAB__NOT_FOUND;
|
||||
dso->symtab_type = ret > 0 ? DSO_BINARY_TYPE__JAVA_JIT :
|
||||
DSO_BINARY_TYPE__NOT_FOUND;
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (machine)
|
||||
root_dir = machine->root_dir;
|
||||
|
||||
/* Iterate over candidate debug images.
|
||||
* On the first pass, only load images if they have a full symtab.
|
||||
* Failing that, do a second pass where we accept .dynsym also
|
||||
*/
|
||||
want_symtab = 1;
|
||||
restart:
|
||||
for (dso->symtab_type = SYMTAB__DEBUGLINK;
|
||||
dso->symtab_type != SYMTAB__NOT_FOUND;
|
||||
dso->symtab_type++) {
|
||||
switch (dso->symtab_type) {
|
||||
case SYMTAB__DEBUGLINK: {
|
||||
char *debuglink;
|
||||
strncpy(name, dso->long_name, size);
|
||||
debuglink = name + dso->long_name_len;
|
||||
while (debuglink != name && *debuglink != '/')
|
||||
debuglink--;
|
||||
if (*debuglink == '/')
|
||||
debuglink++;
|
||||
filename__read_debuglink(dso->long_name, debuglink,
|
||||
size - (debuglink - name));
|
||||
}
|
||||
break;
|
||||
case SYMTAB__BUILD_ID_CACHE:
|
||||
/* skip the locally configured cache if a symfs is given */
|
||||
if (symbol_conf.symfs[0] ||
|
||||
(dso__build_id_filename(dso, name, size) == NULL)) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case SYMTAB__FEDORA_DEBUGINFO:
|
||||
snprintf(name, size, "%s/usr/lib/debug%s.debug",
|
||||
symbol_conf.symfs, dso->long_name);
|
||||
break;
|
||||
case SYMTAB__UBUNTU_DEBUGINFO:
|
||||
snprintf(name, size, "%s/usr/lib/debug%s",
|
||||
symbol_conf.symfs, dso->long_name);
|
||||
break;
|
||||
case SYMTAB__BUILDID_DEBUGINFO: {
|
||||
char build_id_hex[BUILD_ID_SIZE * 2 + 1];
|
||||
for (i = 0; i < DSO_BINARY_TYPE__SYMTAB_CNT; i++) {
|
||||
|
||||
if (!dso->has_build_id)
|
||||
continue;
|
||||
dso->symtab_type = binary_type_symtab[i];
|
||||
|
||||
build_id__sprintf(dso->build_id,
|
||||
sizeof(dso->build_id),
|
||||
build_id_hex);
|
||||
snprintf(name, size,
|
||||
"%s/usr/lib/debug/.build-id/%.2s/%s.debug",
|
||||
symbol_conf.symfs, build_id_hex, build_id_hex + 2);
|
||||
}
|
||||
break;
|
||||
case SYMTAB__SYSTEM_PATH_DSO:
|
||||
snprintf(name, size, "%s%s",
|
||||
symbol_conf.symfs, dso->long_name);
|
||||
break;
|
||||
case SYMTAB__GUEST_KMODULE:
|
||||
if (map->groups && machine)
|
||||
root_dir = machine->root_dir;
|
||||
else
|
||||
root_dir = "";
|
||||
snprintf(name, size, "%s%s%s", symbol_conf.symfs,
|
||||
root_dir, dso->long_name);
|
||||
break;
|
||||
|
||||
case SYMTAB__SYSTEM_PATH_KMODULE:
|
||||
snprintf(name, size, "%s%s", symbol_conf.symfs,
|
||||
dso->long_name);
|
||||
break;
|
||||
default:;
|
||||
}
|
||||
if (dso__binary_type_file(dso, dso->symtab_type,
|
||||
root_dir, name, PATH_MAX))
|
||||
continue;
|
||||
|
||||
/* Name is now the name of the next image to try */
|
||||
fd = open(name, O_RDONLY);
|
||||
@ -2010,9 +2063,9 @@ struct map *machine__new_module(struct machine *machine, u64 start,
|
||||
return NULL;
|
||||
|
||||
if (machine__is_host(machine))
|
||||
dso->symtab_type = SYMTAB__SYSTEM_PATH_KMODULE;
|
||||
dso->symtab_type = DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE;
|
||||
else
|
||||
dso->symtab_type = SYMTAB__GUEST_KMODULE;
|
||||
dso->symtab_type = DSO_BINARY_TYPE__GUEST_KMODULE;
|
||||
map_groups__insert(&machine->kmaps, map);
|
||||
return map;
|
||||
}
|
||||
@ -2564,8 +2617,15 @@ int machine__create_kernel_maps(struct machine *machine)
|
||||
__machine__create_kernel_maps(machine, kernel) < 0)
|
||||
return -1;
|
||||
|
||||
if (symbol_conf.use_modules && machine__create_modules(machine) < 0)
|
||||
pr_debug("Problems creating module maps, continuing anyway...\n");
|
||||
if (symbol_conf.use_modules && machine__create_modules(machine) < 0) {
|
||||
if (machine__is_host(machine))
|
||||
pr_debug("Problems creating module maps, "
|
||||
"continuing anyway...\n");
|
||||
else
|
||||
pr_debug("Problems creating module maps for guest %d, "
|
||||
"continuing anyway...\n", machine->pid);
|
||||
}
|
||||
|
||||
/*
|
||||
* Now that we have all the maps created, just set the ->end of them:
|
||||
*/
|
||||
@ -2905,3 +2965,218 @@ struct map *dso__new_map(const char *name)
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
static int open_dso(struct dso *dso, struct machine *machine)
|
||||
{
|
||||
char *root_dir = (char *) "";
|
||||
char *name;
|
||||
int fd;
|
||||
|
||||
name = malloc(PATH_MAX);
|
||||
if (!name)
|
||||
return -ENOMEM;
|
||||
|
||||
if (machine)
|
||||
root_dir = machine->root_dir;
|
||||
|
||||
if (dso__binary_type_file(dso, dso->data_type,
|
||||
root_dir, name, PATH_MAX)) {
|
||||
free(name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
fd = open(name, O_RDONLY);
|
||||
free(name);
|
||||
return fd;
|
||||
}
|
||||
|
||||
int dso__data_fd(struct dso *dso, struct machine *machine)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
if (dso->data_type != DSO_BINARY_TYPE__NOT_FOUND)
|
||||
return open_dso(dso, machine);
|
||||
|
||||
do {
|
||||
int fd;
|
||||
|
||||
dso->data_type = binary_type_data[i++];
|
||||
|
||||
fd = open_dso(dso, machine);
|
||||
if (fd >= 0)
|
||||
return fd;
|
||||
|
||||
} while (dso->data_type != DSO_BINARY_TYPE__NOT_FOUND);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static void
|
||||
dso_cache__free(struct rb_root *root)
|
||||
{
|
||||
struct rb_node *next = rb_first(root);
|
||||
|
||||
while (next) {
|
||||
struct dso_cache *cache;
|
||||
|
||||
cache = rb_entry(next, struct dso_cache, rb_node);
|
||||
next = rb_next(&cache->rb_node);
|
||||
rb_erase(&cache->rb_node, root);
|
||||
free(cache);
|
||||
}
|
||||
}
|
||||
|
||||
static struct dso_cache*
|
||||
dso_cache__find(struct rb_root *root, u64 offset)
|
||||
{
|
||||
struct rb_node **p = &root->rb_node;
|
||||
struct rb_node *parent = NULL;
|
||||
struct dso_cache *cache;
|
||||
|
||||
while (*p != NULL) {
|
||||
u64 end;
|
||||
|
||||
parent = *p;
|
||||
cache = rb_entry(parent, struct dso_cache, rb_node);
|
||||
end = cache->offset + DSO__DATA_CACHE_SIZE;
|
||||
|
||||
if (offset < cache->offset)
|
||||
p = &(*p)->rb_left;
|
||||
else if (offset >= end)
|
||||
p = &(*p)->rb_right;
|
||||
else
|
||||
return cache;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
dso_cache__insert(struct rb_root *root, struct dso_cache *new)
|
||||
{
|
||||
struct rb_node **p = &root->rb_node;
|
||||
struct rb_node *parent = NULL;
|
||||
struct dso_cache *cache;
|
||||
u64 offset = new->offset;
|
||||
|
||||
while (*p != NULL) {
|
||||
u64 end;
|
||||
|
||||
parent = *p;
|
||||
cache = rb_entry(parent, struct dso_cache, rb_node);
|
||||
end = cache->offset + DSO__DATA_CACHE_SIZE;
|
||||
|
||||
if (offset < cache->offset)
|
||||
p = &(*p)->rb_left;
|
||||
else if (offset >= end)
|
||||
p = &(*p)->rb_right;
|
||||
}
|
||||
|
||||
rb_link_node(&new->rb_node, parent, p);
|
||||
rb_insert_color(&new->rb_node, root);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
dso_cache__memcpy(struct dso_cache *cache, u64 offset,
|
||||
u8 *data, u64 size)
|
||||
{
|
||||
u64 cache_offset = offset - cache->offset;
|
||||
u64 cache_size = min(cache->size - cache_offset, size);
|
||||
|
||||
memcpy(data, cache->data + cache_offset, cache_size);
|
||||
return cache_size;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
dso_cache__read(struct dso *dso, struct machine *machine,
|
||||
u64 offset, u8 *data, ssize_t size)
|
||||
{
|
||||
struct dso_cache *cache;
|
||||
ssize_t ret;
|
||||
int fd;
|
||||
|
||||
fd = dso__data_fd(dso, machine);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
|
||||
do {
|
||||
u64 cache_offset;
|
||||
|
||||
ret = -ENOMEM;
|
||||
|
||||
cache = zalloc(sizeof(*cache) + DSO__DATA_CACHE_SIZE);
|
||||
if (!cache)
|
||||
break;
|
||||
|
||||
cache_offset = offset & DSO__DATA_CACHE_MASK;
|
||||
ret = -EINVAL;
|
||||
|
||||
if (-1 == lseek(fd, cache_offset, SEEK_SET))
|
||||
break;
|
||||
|
||||
ret = read(fd, cache->data, DSO__DATA_CACHE_SIZE);
|
||||
if (ret <= 0)
|
||||
break;
|
||||
|
||||
cache->offset = cache_offset;
|
||||
cache->size = ret;
|
||||
dso_cache__insert(&dso->cache, cache);
|
||||
|
||||
ret = dso_cache__memcpy(cache, offset, data, size);
|
||||
|
||||
} while (0);
|
||||
|
||||
if (ret <= 0)
|
||||
free(cache);
|
||||
|
||||
close(fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t dso_cache_read(struct dso *dso, struct machine *machine,
|
||||
u64 offset, u8 *data, ssize_t size)
|
||||
{
|
||||
struct dso_cache *cache;
|
||||
|
||||
cache = dso_cache__find(&dso->cache, offset);
|
||||
if (cache)
|
||||
return dso_cache__memcpy(cache, offset, data, size);
|
||||
else
|
||||
return dso_cache__read(dso, machine, offset, data, size);
|
||||
}
|
||||
|
||||
ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine,
|
||||
u64 offset, u8 *data, ssize_t size)
|
||||
{
|
||||
ssize_t r = 0;
|
||||
u8 *p = data;
|
||||
|
||||
do {
|
||||
ssize_t ret;
|
||||
|
||||
ret = dso_cache_read(dso, machine, offset, p, size);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Reached EOF, return what we have. */
|
||||
if (!ret)
|
||||
break;
|
||||
|
||||
BUG_ON(ret > size);
|
||||
|
||||
r += ret;
|
||||
p += ret;
|
||||
offset += ret;
|
||||
size -= ret;
|
||||
|
||||
} while (size);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
ssize_t dso__data_read_addr(struct dso *dso, struct map *map,
|
||||
struct machine *machine, u64 addr,
|
||||
u8 *data, ssize_t size)
|
||||
{
|
||||
u64 offset = map->map_ip(map, addr);
|
||||
return dso__data_read_offset(dso, machine, offset, data, size);
|
||||
}
|
||||
|
@ -155,6 +155,21 @@ struct addr_location {
|
||||
s32 cpu;
|
||||
};
|
||||
|
||||
enum dso_binary_type {
|
||||
DSO_BINARY_TYPE__KALLSYMS = 0,
|
||||
DSO_BINARY_TYPE__GUEST_KALLSYMS,
|
||||
DSO_BINARY_TYPE__JAVA_JIT,
|
||||
DSO_BINARY_TYPE__DEBUGLINK,
|
||||
DSO_BINARY_TYPE__BUILD_ID_CACHE,
|
||||
DSO_BINARY_TYPE__FEDORA_DEBUGINFO,
|
||||
DSO_BINARY_TYPE__UBUNTU_DEBUGINFO,
|
||||
DSO_BINARY_TYPE__BUILDID_DEBUGINFO,
|
||||
DSO_BINARY_TYPE__SYSTEM_PATH_DSO,
|
||||
DSO_BINARY_TYPE__GUEST_KMODULE,
|
||||
DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE,
|
||||
DSO_BINARY_TYPE__NOT_FOUND,
|
||||
};
|
||||
|
||||
enum dso_kernel_type {
|
||||
DSO_TYPE_USER = 0,
|
||||
DSO_TYPE_KERNEL,
|
||||
@ -167,19 +182,31 @@ enum dso_swap_type {
|
||||
DSO_SWAP__YES,
|
||||
};
|
||||
|
||||
#define DSO__DATA_CACHE_SIZE 4096
|
||||
#define DSO__DATA_CACHE_MASK ~(DSO__DATA_CACHE_SIZE - 1)
|
||||
|
||||
struct dso_cache {
|
||||
struct rb_node rb_node;
|
||||
u64 offset;
|
||||
u64 size;
|
||||
char data[0];
|
||||
};
|
||||
|
||||
struct dso {
|
||||
struct list_head node;
|
||||
struct rb_root symbols[MAP__NR_TYPES];
|
||||
struct rb_root symbol_names[MAP__NR_TYPES];
|
||||
struct rb_root cache;
|
||||
enum dso_kernel_type kernel;
|
||||
enum dso_swap_type needs_swap;
|
||||
enum dso_binary_type symtab_type;
|
||||
enum dso_binary_type data_type;
|
||||
u8 adjust_symbols:1;
|
||||
u8 has_build_id:1;
|
||||
u8 hit:1;
|
||||
u8 annotate_warned:1;
|
||||
u8 sname_alloc:1;
|
||||
u8 lname_alloc:1;
|
||||
unsigned char symtab_type;
|
||||
u8 sorted_by_name;
|
||||
u8 loaded;
|
||||
u8 build_id[BUILD_ID_SIZE];
|
||||
@ -253,21 +280,6 @@ size_t dso__fprintf_symbols_by_name(struct dso *dso,
|
||||
enum map_type type, FILE *fp);
|
||||
size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp);
|
||||
|
||||
enum symtab_type {
|
||||
SYMTAB__KALLSYMS = 0,
|
||||
SYMTAB__GUEST_KALLSYMS,
|
||||
SYMTAB__JAVA_JIT,
|
||||
SYMTAB__DEBUGLINK,
|
||||
SYMTAB__BUILD_ID_CACHE,
|
||||
SYMTAB__FEDORA_DEBUGINFO,
|
||||
SYMTAB__UBUNTU_DEBUGINFO,
|
||||
SYMTAB__BUILDID_DEBUGINFO,
|
||||
SYMTAB__SYSTEM_PATH_DSO,
|
||||
SYMTAB__GUEST_KMODULE,
|
||||
SYMTAB__SYSTEM_PATH_KMODULE,
|
||||
SYMTAB__NOT_FOUND,
|
||||
};
|
||||
|
||||
char dso__symtab_origin(const struct dso *dso);
|
||||
void dso__set_long_name(struct dso *dso, char *name);
|
||||
void dso__set_build_id(struct dso *dso, void *build_id);
|
||||
@ -304,4 +316,14 @@ bool symbol_type__is_a(char symbol_type, enum map_type map_type);
|
||||
|
||||
size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp);
|
||||
|
||||
int dso__binary_type_file(struct dso *dso, enum dso_binary_type type,
|
||||
char *root_dir, char *file, size_t size);
|
||||
|
||||
int dso__data_fd(struct dso *dso, struct machine *machine);
|
||||
ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine,
|
||||
u64 offset, u8 *data, ssize_t size);
|
||||
ssize_t dso__data_read_addr(struct dso *dso, struct map *map,
|
||||
struct machine *machine, u64 addr,
|
||||
u8 *data, ssize_t size);
|
||||
int dso__test_data(void);
|
||||
#endif /* __PERF_SYMBOL */
|
||||
|
@ -110,8 +110,17 @@ int perf_target__strerror(struct perf_target *target, int errnum,
|
||||
int idx;
|
||||
const char *msg;
|
||||
|
||||
BUG_ON(buflen > 0);
|
||||
|
||||
if (errnum >= 0) {
|
||||
strerror_r(errnum, buf, buflen);
|
||||
const char *err = strerror_r(errnum, buf, buflen);
|
||||
|
||||
if (err != buf) {
|
||||
size_t len = strlen(err);
|
||||
char *c = mempcpy(buf, err, min(buflen - 1, len));
|
||||
*c = '\0';
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user