perf fixes
Subsystems (2)
Linus,
Please pull the latest perf-urgent-for-linus git tree from:
git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git perf-urgent-for-linus
HEAD: db0dc75d6403b6663c0eab4c6ccb672eb9b2ed72 perf/x86: Check user address explicitly in copy_from_user_nmi()
A bit larger than what I'd wish for - half of it is due to hw driver updates to Intel Ivy-Bridge which info got recently released, cycles:pp should work there now too, amongst other things. (but we are generally making exceptions for hardware enablement of this type.)
There are also callchain fixes in it - responding to mostly theoretical (but valid) concerns. The tooling side sports perf.data endianness/portability fixes which did not make it for the merge window - and various other fixes as well.
Thanks,
Ingo
------------------>
Arnaldo Carvalho de Melo (5):
perf report: Use the right symbol for annotation
perf annotate browser: Fix help window entry for navigating to hottest line perf stat: Initialize default events wrt exclude_{guest,host} perf tools: Fix make tarballs
perf tools: Make --version show kernel version instead of pull req tag
Arun Sharma (4):
perf/x86: Allow multiple stacks
perf: Limit callchains to 127
perf/x86: Check if user fp is valid
perf/x86: Check user address explicitly in copy_from_user_nmi()
Avik Sil (1):
perf tools: Fix pager on minimal-install embedded systems
David Ahern (1):
perf script: Fix regression in callchain dso name
Jiri Olsa (3):
perf symbols: Handle different endians properly during symbol load perf session: Handle endianity swap on sample_id_all header data perf evsel: Fix 32 bit values endianity swap for sample_id_all header
Masami Hiramatsu (1):
x86/decoder: Fix bsr/bsf/jmpe decoding with operand-size prefix
Namhyung Kim (5):
perf callchain: Make callchain cursors TLS
perf tools: Check if callchain is corrupted
perf tools: Update ioctl documentation for PERF_IOC_FLAG_GROUP perf evlist: Pass third argument to ioctl explicitly
perf: Remove duplicate invocation on perf_event_for_each
Peter Zijlstra (4):
perf/x86: Fix Intel shared extra MSR allocation perf/x86: Implement cycles:p for SNB/IVB perf/x86: Enable/Add IvyBridge hardware support perf/x86: Update SNB PEBS constraints
Srikar Dronamraju (2):
perf symbols: Check for valid dso before creating map perf uprobes: Remove unnecessary check before strlist__delete
arch/x86/include/asm/uaccess.h | 12 +-- arch/x86/kernel/cpu/perf_event.c | 11 ++- arch/x86/kernel/cpu/perf_event.h | 2 + arch/x86/kernel/cpu/perf_event_intel.c | 145 ++++++++++++++++++++++-------- arch/x86/kernel/cpu/perf_event_intel_ds.c | 9 +- arch/x86/lib/usercopy.c | 4 + arch/x86/lib/x86-opcode-map.txt | 8 +- arch/x86/tools/gen-insn-attr-x86.awk | 14 +-- include/linux/perf_event.h | 4 +- kernel/events/core.c | 1 - tools/perf/MANIFEST | 2 + tools/perf/builtin-report.c | 4 +- tools/perf/builtin-stat.c | 8 +- tools/perf/builtin-top.c | 2 +- tools/perf/design.txt | 7 +- tools/perf/ui/browsers/annotate.c | 2 +- tools/perf/util/PERF-VERSION-GEN | 2 +- tools/perf/util/callchain.c | 2 + tools/perf/util/callchain.h | 2 + tools/perf/util/evlist.c | 17 +++- tools/perf/util/evlist.h | 4 + tools/perf/util/evsel.c | 29 ++++-- tools/perf/util/hist.c | 7 +- tools/perf/util/hist.h | 2 - tools/perf/util/pager.c | 4 + tools/perf/util/probe-event.c | 8 +- tools/perf/util/session.c | 97 +++++++++++++++----- tools/perf/util/symbol.c | 38 +++++++- tools/perf/util/symbol.h | 30 +++++++ 29 files changed, 357 insertions(+), 120 deletions(-)
arch/x86/include/asm/uaccess.h +6 -6
@@ -33,9 +33,8 @@#define segment_eq (a, b) ((a).seg == (b).seg)#define user_addr_max () (current_thread_info()->addr_limit.seg) -#define __addr_ok (addr) \ - ((unsigned long __force)(addr) < \ - (current_thread_info()->addr_limit.seg)) +#define __addr_ok (addr) \ + ((unsigned long __force)(addr) < user_addr_max())/* * Test whether a block of memory is a valid user space address.
@@ -47,14 +46,14 @@* This needs 33-bit (65-bit for x86_64) arithmetic. We have a carry... */ -#define __range_not_ok (addr, size) \ +#define __range_not_ok (addr, size, limit) \ ({ \ unsigned long flag, roksum; \ __chk_user_ptr(addr); \ asm("add %3,%1 ; sbb %0,%0 ; cmp %1,%4 ; sbb $0,%0" \ : "=&r" (flag), "=r" (roksum) \ : "1" (addr), "g" ((long)(size)), \ - "rm" (current_thread_info()->addr_limit.seg)); \ + "rm" (limit)); \ flag; \ })
@@ -77,7 +76,8 @@* checks that the pointer is in the user space range - after calling * this function, memory access functions may still return -EFAULT. */ -#define access_ok (type, addr, size) (likely(__range_not_ok(addr, size) == 0)) +#define access_ok (type, addr, size) \ + (likely(__range_not_ok(addr, size, user_addr_max()) == 0))/* * The exception table consists of pairs of addresses relative to the
arch/x86/kernel/cpu/perf_event.c +9 -2
@@ -1496,6 +1496,7 @@ static struct cpu_hw_events *allocate_fake_cpuc(void)if (!cpuc->shared_regs) goto error; } + cpuc->is_fake =1 ;return cpuc; error:free_fake_cpuc (cpuc);
@@ -1756,6 +1757,12 @@ perf_callchain_kernel(struct perf_callchain_entry *entry, struct pt_regs *regs)dump_trace (NULL , regs,NULL ,0 , &backtrace_ops, entry); } +static inline int +valid_user_frame (const void __user *fp,unsigned long size) +{ +return (__range_not_ok (fp, size,TASK_SIZE ) ==0 ); +} +#ifdef CONFIG_COMPAT #include <asm/compat.h>
@@ -1780,7 +1787,7 @@ perf_callchain_user32(struct pt_regs *regs, struct perf_callchain_entry *entry)if (bytes !=sizeof (frame))break ; -if (fp <compat_ptr (regs->sp)) +if (!valid_user_frame (fp,sizeof (frame)))break ;perf_callchain_store (entry, frame.return_address);
@@ -1826,7 +1833,7 @@ perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs)if (bytes !=sizeof (frame))break ; -if ((unsigned long )fp < regs->sp) +if (!valid_user_frame (fp,sizeof (frame)))break ;perf_callchain_store (entry, frame.return_address);
arch/x86/kernel/cpu/perf_event.h +2 -0
@@ -117,6 +117,7 @@ struct cpu_hw_events {struct perf_event *event_list[X86_PMC_IDX_MAX ];/* in enabled order */ unsigned int group_flag; +int is_fake;/* * Intel DebugStore bits
@@ -364,6 +365,7 @@ struct x86_pmu {int pebs_record_size;void (*drain_pebs)(struct pt_regs *regs);struct event_constraint *pebs_constraints; +void (*pebs_aliases)(struct perf_event *event);/* * Intel LBR
arch/x86/kernel/cpu/perf_event_intel.c +108 -37
228 lines not on this page · raw message
arch/x86/kernel/cpu/perf_event_intel_ds.c +1 -8
@@ -400,14 +400,7 @@ struct event_constraint intel_snb_pebs_event_constraints[] = {INTEL_EVENT_CONSTRAINT (0xc4 ,0xf ),/* BR_INST_RETIRED.* */ INTEL_EVENT_CONSTRAINT (0xc5 ,0xf ),/* BR_MISP_RETIRED.* */ INTEL_EVENT_CONSTRAINT (0xcd ,0x8 ),/* MEM_TRANS_RETIRED.* */ -INTEL_UEVENT_CONSTRAINT (0x11d0 ,0xf ),/* MEM_UOP_RETIRED.STLB_MISS_LOADS */ -INTEL_UEVENT_CONSTRAINT (0x12d0 ,0xf ),/* MEM_UOP_RETIRED.STLB_MISS_STORES */ -INTEL_UEVENT_CONSTRAINT (0x21d0 ,0xf ),/* MEM_UOP_RETIRED.LOCK_LOADS */ -INTEL_UEVENT_CONSTRAINT (0x22d0 ,0xf ),/* MEM_UOP_RETIRED.LOCK_STORES */ -INTEL_UEVENT_CONSTRAINT (0x41d0 ,0xf ),/* MEM_UOP_RETIRED.SPLIT_LOADS */ -INTEL_UEVENT_CONSTRAINT (0x42d0 ,0xf ),/* MEM_UOP_RETIRED.SPLIT_STORES */ -INTEL_UEVENT_CONSTRAINT (0x81d0 ,0xf ),/* MEM_UOP_RETIRED.ANY_LOADS */ -INTEL_UEVENT_CONSTRAINT (0x82d0 ,0xf ),/* MEM_UOP_RETIRED.ANY_STORES */ +INTEL_EVENT_CONSTRAINT (0xd0 ,0xf ),/* MEM_UOP_RETIRED.* */ INTEL_EVENT_CONSTRAINT (0xd1 ,0xf ),/* MEM_LOAD_UOPS_RETIRED.* */ INTEL_EVENT_CONSTRAINT (0xd2 ,0xf ),/* MEM_LOAD_UOPS_LLC_HIT_RETIRED.* */ INTEL_UEVENT_CONSTRAINT(0x02d4, 0xf), /* MEM_LOAD_UOPS_MISC_RETIRED.LLC_MISS */
arch/x86/lib/usercopy.c +4 -0
@@ -8,6 +8,7 @@#include <linux/module.h> #include <asm/word-at-a-time.h> +#include <linux/sched.h> /* * best effort, GUP based copy_from_user() that is NMI-safe
@@ -21,6 +22,9 @@ copy_from_user_nmi(void *to, const void __user *from, unsigned long n)void *map;int ret; +if (__range_not_ok (from, n,TASK_SIZE ) ==0 ) +return len; + do { ret = __get_user_pages_fast(addr, 1, 0, &page); if (!ret)
arch/x86/lib/x86-opcode-map.txt +4 -4
@@ -28,7 +28,7 @@ # - (66): the last prefix is 0x66 # - (F3): the last prefix is 0xF3 # - (F2): the last prefix is 0xF2 -# +# - (!F3) : the last prefix is not 0xF3 (including non-last prefix case) Table: one byte opcode Referrer:
@@ -515,12 +515,12 @@ b4: LFS Gv,Mp b5: LGS Gv,Mp b6: MOVZX Gv,Eb b7: MOVZX Gv,Ew -b8: JMPE | POPCNT Gv,Ev (F3) +b8: JMPE (!F3) | POPCNT Gv,Ev (F3) b9: Grp10 (1A) ba: Grp8 Ev,Ib (1A) bb: BTC Ev,Gv -bc: BSF Gv,Ev | TZCNT Gv,Ev (F3) -bd: BSR Gv,Ev | LZCNT Gv,Ev (F3) +bc: BSF Gv,Ev (!F3) | TZCNT Gv,Ev (F3) +bd: BSR Gv,Ev (!F3) | LZCNT Gv,Ev (F3) be: MOVSX Gv,Eb bf: MOVSX Gv,Ew # 0x0f 0xc0-0xcf
arch/x86/tools/gen-insn-attr-x86.awk +9 -5
@@ -66,9 +66,10 @@ BEGIN { rex_expr = "^REX(\\.[XRWB]+)*" fpu_expr = "^ESC" # TODO - lprefix1_expr = "\\(66\\)" + lprefix1_expr = "\\((66|!F3)\\)" lprefix2_expr = "\\(F3\\)" - lprefix3_expr = "\\(F2\\)" + lprefix3_expr = "\\((F2|!F3)\\)" + lprefix_expr = "\\((66|F2|F3)\\)" max_lprefix = 4 # All opcodes starting with lower-case 'v' or with (v1) superscript
@@ -333,13 +334,16 @@ function convert_operands(count,opnd, i,j,imm,mod) if (match(ext, lprefix1_expr)) { lptable1[idx] = add_flags(lptable1[idx],flags) variant = "INAT_VARIANT" - } else if (match(ext, lprefix2_expr)) { + } + if (match(ext, lprefix2_expr)) { lptable2[idx] = add_flags(lptable2[idx],flags) variant = "INAT_VARIANT" - } else if (match(ext, lprefix3_expr)) { + } + if (match(ext, lprefix3_expr)) { lptable3[idx] = add_flags(lptable3[idx],flags) variant = "INAT_VARIANT" - } else { + } + if (!match(ext, lprefix_expr)){ table[idx] = add_flags(table[idx],flags) } }
include/linux/perf_event.h +2 -2
@@ -555,6 +555,8 @@ enum perf_event_type { PERF_RECORD_MAX, /* non-ABI */ }; +#define PERF_MAX_STACK_DEPTH 127 +enum perf_callchain_context {PERF_CONTEXT_HV = (__u64)-32 ,PERF_CONTEXT_KERNEL = (__u64)-128 ,
@@ -609,8 +611,6 @@ struct perf_guest_info_callbacks {#include <linux/sysfs.h> #include <asm/local.h> -#define PERF_MAX_STACK_DEPTH 255 -struct perf_callchain_entry {__u64 nr;__u64 ip[PERF_MAX_STACK_DEPTH ];
kernel/events/core.c +0 -1
@@ -3181,7 +3181,6 @@ static void perf_event_for_each(struct perf_event *event, event = event->group_leader;perf_event_for_each_child (event, func); -func (event);list_for_each_entry (sibling, &event->sibling_list, group_entry)perf_event_for_each_child (sibling, func);mutex_unlock (&ctx->mutex);
tools/perf/MANIFEST +2 -0
@@ -1,4 +1,6 @@ tools/perf +tools/scripts +tools/lib/traceevent include/linux/const.h include/linux/perf_event.h include/linux/rbtree.h
tools/perf/builtin-report.c +2 -2
@@ -152,7 +152,7 @@ static int perf_evsel__add_hist_entry(struct perf_evsel *evsel,if (symbol_conf.use_callchain) { err =callchain_append (he->callchain, - &evsel->hists.callchain_cursor, + &callchain_cursor, sample->period);if (err)return err;
@@ -162,7 +162,7 @@ static int perf_evsel__add_hist_entry(struct perf_evsel *evsel,* so we don't allocated the extra space needed because the stdio * code will not use it. */ -if (al->sym !=NULL && use_browser >0 ) { +if (he->ms.sym !=NULL && use_browser >0 ) {struct annotation *notes =symbol__annotation (he->ms.sym);assert (evsel !=NULL );
tools/perf/builtin-stat.c +4 -4
@@ -1129,7 +1129,7 @@ static int add_default_attributes(void)return 0 ;if (!evsel_list->nr_entries) { -if (perf_evlist__add_attrs_array (evsel_list, default_attrs) <0 ) +if (perf_evlist__add_default_attrs (evsel_list, default_attrs) <0 )return -1 ; }
@@ -1139,21 +1139,21 @@ static int add_default_attributes(void)return 0 ;/* Append detailed run extra attributes: */ -if (perf_evlist__add_attrs_array (evsel_list, detailed_attrs) <0 ) +if (perf_evlist__add_default_attrs (evsel_list, detailed_attrs) <0 )return -1 ;if (detailed_run <2 )return 0 ;/* Append very detailed run extra attributes: */ -if (perf_evlist__add_attrs_array (evsel_list, very_detailed_attrs) <0 ) +if (perf_evlist__add_default_attrs (evsel_list, very_detailed_attrs) <0 )return -1 ;if (detailed_run <3 )return 0 ;/* Append very, very detailed run extra attributes: */ -return perf_evlist__add_attrs_array (evsel_list, very_very_detailed_attrs); +return perf_evlist__add_default_attrs (evsel_list, very_very_detailed_attrs); }int cmd_stat (int argc,const char **argv,const char *prefix__used )
tools/perf/builtin-top.c +1 -1
@@ -787,7 +787,7 @@ static void perf_event__process_sample(struct perf_tool *tool, }if (symbol_conf.use_callchain) { - err =callchain_append (he->callchain, &evsel->hists.callchain_cursor, + err =callchain_append (he->callchain, &callchain_cursor, sample->period);if (err)return ;
tools/perf/design.txt +4 -3
@@ -409,14 +409,15 @@ Counters can be enabled and disabled in two ways: via ioctl and via prctl. When a counter is disabled, it doesn't count or generate events but does continue to exist and maintain its count value. -An individual counter or counter group can be enabled with +An individual counter can be enabled with - ioctl(fd, PERF_EVENT_IOC_ENABLE); + ioctl(fd, PERF_EVENT_IOC_ENABLE, 0); or disabled with - ioctl(fd, PERF_EVENT_IOC_DISABLE); + ioctl(fd, PERF_EVENT_IOC_DISABLE, 0); +For a counter group, pass PERF_IOC_FLAG_GROUP as the third argument. Enabling or disabling the leader of a group enables or disables the whole group; that is, while the group leader is disabled, none of the counters in the group will count. Enabling or disabling a member of a
tools/perf/ui/browsers/annotate.c +1 -1
@@ -668,7 +668,7 @@ static int annotate_browser__run(struct annotate_browser *browser, int evidx,"q/ESC/CTRL+C Exit\n\n" "-> Go to target\n" "<- Exit\n" -"h Cycle thru hottest instructions\n" +"H Cycle thru hottest instructions\n" "j Toggle showing jump to target arrows\n" "J Toggle showing number of jump sources on targets\n" "n Search next string\n"
tools/perf/util/PERF-VERSION-GEN +1 -1
@@ -12,7 +12,7 @@ LF=' # First check if there is a .git to get the version from git describe # otherwise try to get the version from the kernel makefile if test -d ../../.git -o -f ../../.git && - VN=$(git describe --abbrev=4 HEAD 2>/dev/null) && + VN=$(git describe --match 'v[0-9].[0-9]*' --abbrev=4 HEAD 2>/dev/null) && case "$VN" in *$LF*) (exit 1) ;; v[0-9]*)
tools/perf/util/callchain.c +2 -0
@@ -18,6 +18,8 @@#include "util.h" #include "callchain.h" +__threadstruct callchain_cursor callchain_cursor; +bool ip_callchain__valid (struct ip_callchain *chain,const union perf_event *event) {
tools/perf/util/callchain.h +2 -0
@@ -76,6 +76,8 @@ struct callchain_cursor {struct callchain_cursor_node *curr; }; +extern __threadstruct callchain_cursor callchain_cursor; +static inline void callchain_init (struct callchain_root *root) {INIT_LIST_HEAD (&root->node.siblings);
tools/perf/util/evlist.c +15 -2
@@ -159,6 +159,17 @@ out_delete_partial_list:return -1 ; } +int __perf_evlist__add_default_attrs (struct perf_evlist *evlist, +struct perf_event_attr *attrs,size_t nr_attrs) +{ +size_t i; + +for (i =0 ; i < nr_attrs; i++) +event_attr_init (attrs + i); + +return perf_evlist__add_attrs (evlist, attrs, nr_attrs); +} +static int trace_event__id (const char *evname) {char *filename, *colon;
@@ -263,7 +274,8 @@ void perf_evlist__disable(struct perf_evlist *evlist)for (cpu =0 ; cpu < evlist->cpus->nr; cpu++) {list_for_each_entry (pos, &evlist->entries, node) {for (thread =0 ; thread < evlist->threads->nr; thread++) -ioctl (FD (pos, cpu, thread),PERF_EVENT_IOC_DISABLE ); +ioctl (FD (pos, cpu, thread), +PERF_EVENT_IOC_DISABLE ,0 ); } } }
@@ -276,7 +288,8 @@ void perf_evlist__enable(struct perf_evlist *evlist)for (cpu =0 ; cpu < evlist->cpus->nr; cpu++) {list_for_each_entry (pos, &evlist->entries, node) {for (thread =0 ; thread < evlist->threads->nr; thread++) -ioctl (FD (pos, cpu, thread),PERF_EVENT_IOC_ENABLE ); +ioctl (FD (pos, cpu, thread), +PERF_EVENT_IOC_ENABLE ,0 ); } } }
tools/perf/util/evlist.h +4 -0
@@ -54,6 +54,8 @@ void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry);int perf_evlist__add_default (struct perf_evlist *evlist);int perf_evlist__add_attrs (struct perf_evlist *evlist,struct perf_event_attr *attrs,size_t nr_attrs); +int __perf_evlist__add_default_attrs (struct perf_evlist *evlist, +struct perf_event_attr *attrs,size_t nr_attrs);int perf_evlist__add_tracepoints (struct perf_evlist *evlist,const char *tracepoints[],size_t nr_tracepoints); int perf_evlist__set_tracepoints_handlers(struct perf_evlist *evlist,
@@ -62,6 +64,8 @@ int perf_evlist__set_tracepoints_handlers(struct perf_evlist *evlist,#define perf_evlist__add_attrs_array (evlist, array) \ perf_evlist__add_attrs(evlist, array, ARRAY_SIZE(array)) +#define perf_evlist__add_default_attrs (evlist, array) \ + __perf_evlist__add_default_attrs(evlist, array, ARRAY_SIZE(array))#define perf_evlist__add_tracepoints_array (evlist, array) \ perf_evlist__add_tracepoints(evlist, array, ARRAY_SIZE(array))
tools/perf/util/evsel.c +22 -7
@@ -494,16 +494,24 @@ int perf_evsel__open_per_thread(struct perf_evsel *evsel, }static int perf_event__parse_id_sample (const union perf_event *event,u64 type, -struct perf_sample *sample) +struct perf_sample *sample, +bool swapped) {const u64 *array = event->sample.array; +union u64_swap u; array += ((event->header.size -sizeof (event->header)) /sizeof (u64)) -1 ;if (type &PERF_SAMPLE_CPU ) { -u32 *p = (u32 *)array; - sample->cpu = *p; + u.val64 = *array; +if (swapped) { +/* undo swap of u64, then swap on individual u32s */ + u.val64 =bswap_64 (u.val64); + u.val32[0 ] =bswap_32 (u.val32[0 ]); + } + + sample->cpu = u.val32[0 ]; array--; }
@@ -523,9 +531,16 @@ static int perf_event__parse_id_sample(const union perf_event *event, u64 type, }if (type &PERF_SAMPLE_TID ) { -u32 *p = (u32 *)array; - sample->pid = p[0 ]; - sample->tid = p[1 ]; + u.val64 = *array; +if (swapped) { +/* undo swap of u64, then swap on individual u32s */ + u.val64 =bswap_64 (u.val64); + u.val32[0 ] =bswap_32 (u.val32[0 ]); + u.val32[1 ] =bswap_32 (u.val32[1 ]); + } + + sample->pid = u.val32[0 ]; + sample->tid = u.val32[1 ]; }return 0 ;
@@ -562,7 +577,7 @@ int perf_event__parse_sample(const union perf_event *event, u64 type,if (event->header.type !=PERF_RECORD_SAMPLE ) {if (!sample_id_all)return 0 ; -return perf_event__parse_id_sample (event, type, data); +return perf_event__parse_id_sample (event, type, data, swapped); } array = event->sample.array;
tools/perf/util/hist.c +4 -3
@@ -378,7 +378,7 @@ void hist_entry__free(struct hist_entry *he)* collapse the histogram */ -static bool hists__collapse_insert_entry (struct hists *hists, +static bool hists__collapse_insert_entry (struct hists *hists__used ,struct rb_root *root,struct hist_entry *he) {
@@ -397,8 +397,9 @@ static bool hists__collapse_insert_entry(struct hists *hists, iter->period += he->period; iter->nr_events += he->nr_events;if (symbol_conf.use_callchain) { -callchain_cursor_reset (&hists->callchain_cursor); -callchain_merge (&hists->callchain_cursor, iter->callchain, +callchain_cursor_reset (&callchain_cursor); +callchain_merge (&callchain_cursor, + iter->callchain, he->callchain); }hist_entry__free (he);
tools/perf/util/hist.h +0 -2
@@ -67,8 +67,6 @@ struct hists {struct events_stats stats;u64 event_stream;u16 col_len[HISTC_NR_COLS ]; -/* Best would be to reuse the session callchain cursor */ -struct callchain_cursor callchain_cursor; }; struct hist_entry *__hists__add_entry(struct hists *self,
tools/perf/util/pager.c +4 -0
@@ -57,6 +57,10 @@ void setup_pager(void) }if (!pager) pager =getenv ("PAGER" ); +if (!pager) { +if (!access ("/usr/bin/pager" ,X_OK )) + pager ="/usr/bin/pager" ; + }if (!pager) pager ="less" ;else if (!*pager || !strcmp (pager,"cat" ))
tools/perf/util/probe-event.c +2 -6
@@ -2164,16 +2164,12 @@ int del_perf_probe_events(struct strlist *dellist) error:if (kfd >=0 ) { -if (namelist) -strlist__delete (namelist); - +strlist__delete (namelist);close (kfd); }if (ufd >=0 ) { -if (unamelist) -strlist__delete (unamelist); - +strlist__delete (unamelist);close (ufd); }
tools/perf/util/session.c +76 -21
216 lines not on this page · raw message
tools/perf/util/symbol.c +36 -2
@@ -323,6 +323,7 @@ struct dso *dso__new(const char *name) dso->sorted_by_name =0 ; dso->has_build_id =0 ; dso->kernel =DSO_TYPE_USER ; + dso->needs_swap =DSO_SWAP__UNSET ;INIT_LIST_HEAD (&dso->node); }
@@ -1156,6 +1157,33 @@ static size_t elf_addr_to_index(Elf *elf, GElf_Addr addr)return -1 ; } +static int dso__swap_init (struct dso *dso,unsigned char eidata) +{ +static unsigned int const endian =1 ; + + dso->needs_swap =DSO_SWAP__NO ; + +switch (eidata) { +case ELFDATA2LSB : +/* We are big endian, DSO is little endian. */ +if (*(unsigned char const *)&endian !=1 ) + dso->needs_swap =DSO_SWAP__YES ; +break ; + +case ELFDATA2MSB : +/* We are little endian, DSO is big endian. */ +if (*(unsigned char const *)&endian !=0 ) + dso->needs_swap =DSO_SWAP__YES ; +break ; + +default : +pr_err ("unrecognized DSO data encoding %d\n" , eidata); +return -EINVAL ; + } + +return 0 ; +} +static int dso__load_sym (struct dso *dso,struct map *map,const char *name,int fd,symbol_filter_t filter,int kmodule,int want_symtab)
@@ -1187,6 +1215,9 @@ static int dso__load_sym(struct dso *dso, struct map *map, const char *name, goto out_elf_end; } +if (dso__swap_init (dso, ehdr.e_ident[EI_DATA ])) + goto out_elf_end; +/* Always reject images with a mismatched build-id: */ if (dso->has_build_id) {u8 build_id[BUILD_ID_SIZE ];
@@ -1272,7 +1303,7 @@ static int dso__load_sym(struct dso *dso, struct map *map, const char *name,if (opdsec && sym.st_shndx == opdidx) {u32 offset = sym.st_value - opdshdr.sh_addr;u64 *opd = opddata->d_buf + offset; - sym.st_value = *opd; + sym.st_value =DSO__SWAP (dso, u64, *opd); sym.st_shndx =elf_addr_to_index (elf, sym.st_value); }
@@ -2786,8 +2817,11 @@ int machine__load_vmlinux_path(struct machine *machine, enum map_type type,struct map *dso__new_map (const char *name) { +struct map *map =NULL ;struct dso *dso =dso__new (name); -struct map *map =map__new2 (0 , dso,MAP__FUNCTION ); + +if (dso) + map =map__new2 (0 , dso,MAP__FUNCTION );return map; }
tools/perf/util/symbol.h +30 -0
@@ -9,6 +9,7 @@#include <linux/list.h> #include <linux/rbtree.h> #include <stdio.h> +#include <byteswap.h> #ifdef HAVE_CPLUS_DEMANGLE extern char *cplus_demangle (const char *,int );
@@ -160,11 +161,18 @@ enum dso_kernel_type {DSO_TYPE_GUEST_KERNEL }; +enum dso_swap_type { +DSO_SWAP__UNSET , +DSO_SWAP__NO , +DSO_SWAP__YES , +}; +struct dso {struct list_head node;struct rb_root symbols[MAP__NR_TYPES ];struct rb_root symbol_names[MAP__NR_TYPES ];enum dso_kernel_type kernel; +enum dso_swap_type needs_swap;u8 adjust_symbols:1 ;u8 has_build_id:1 ;u8 hit:1 ;
@@ -182,6 +190,28 @@ struct dso {char name[0 ]; }; +#define DSO__SWAP (dso, type, val) \ +({ \ + type ____r = val; \ + BUG_ON(dso->needs_swap == DSO_SWAP__UNSET); \ + if (dso->needs_swap == DSO_SWAP__YES) { \ + switch (sizeof(____r)) { \ + case 2: \ + ____r = bswap_16(val); \ + break; \ + case 4: \ + ____r = bswap_32(val); \ + break; \ + case 8: \ + ____r = bswap_64(val); \ + break; \ + default: \ + BUG_ON(1); \ + } \ + } \ + ____r; \ +}) +struct dso *dso__new (const char *name);void dso__delete (struct dso *dso);