Re: [BUG] perf cross-compile error dual to fixdep not host-exe
hi, Jirka On 2015/9/30 14:13, Jiri Olsa wrote: On Wed, Sep 30, 2015 at 11:18:20AM +0800, He Kuang wrote: Hi, perf cross-compile error dual to fixdep is not a host executable, first bad commit is 7c422f557266("tools build: Build fixdep helper from perf and basic libs") Cross-compiling an aarch64 target on x86_64 host, error like this: $ make ARCH=aarch64 O=xx/aarch64 CROSS_COMPILE=aarch64-linux-gnu ... make[3]: *** [xx/aarch64/parse-utils.o] Error 126 make[3]: *** Waiting for unfinished jobs /bin/sh: xx/aarch64//fixdep: cannot execute binary file $ uname -a x86_64 x86_64 x86_64 GNU/Linux $ file xx/aarch64//fixdep xx/aarch64//fixdep : ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1, for GNU/Linux 3.7.0, not stripped hum, we need fixdep to stay the host arch.. I should have seen it :-\ could you please check attached patch? thanks, jirka It does not work, 'fixdep' still be compiled as target executable. Thank you. --- diff --git a/tools/build/Makefile b/tools/build/Makefile index a93036272d43..648897694992 100644 --- a/tools/build/Makefile +++ b/tools/build/Makefile @@ -5,15 +5,6 @@ endif include $(srctree)/tools//scripts/Makefile.include -define allow-override - $(if $(or $(findstring environment,$(origin $(1))),\ -$(findstring command line,$(origin $(1,,\ -$(eval $(1) = $(2))) -endef - -$(call allow-override,CC,$(CROSS_COMPILE)gcc) -$(call allow-override,LD,$(CROSS_COMPILE)ld) - ifeq ($(V),1) Q = else -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH] perf tools: Support bpf prologue for arm64
This patch implements arch_get_reg_info() for arm64 to enable HAVE_BPF_PROLOGUE feature. For arm64, structure pt_regs is not composed by fields of register names but an array of regs, so here we simply multiply fixed register size by index number to get the byte offset. Signed-off-by: He Kuang --- tools/perf/arch/arm64/Makefile | 1 + tools/perf/arch/arm64/util/dwarf-regs.c | 26 ++ 2 files changed, 27 insertions(+) diff --git a/tools/perf/arch/arm64/Makefile b/tools/perf/arch/arm64/Makefile index 7fbca17..1256e6e 100644 --- a/tools/perf/arch/arm64/Makefile +++ b/tools/perf/arch/arm64/Makefile @@ -1,3 +1,4 @@ ifndef NO_DWARF PERF_HAVE_DWARF_REGS := 1 endif +PERF_HAVE_ARCH_GET_REG_INFO := 1 diff --git a/tools/perf/arch/arm64/util/dwarf-regs.c b/tools/perf/arch/arm64/util/dwarf-regs.c index d49efeb..cb2c50a 100644 --- a/tools/perf/arch/arm64/util/dwarf-regs.c +++ b/tools/perf/arch/arm64/util/dwarf-regs.c @@ -10,6 +10,10 @@ #include #include +#include +#include + +#define PT_REG_SIZE (sizeof(((struct user_pt_regs *)0)->regs[0])) struct pt_regs_dwarfnum { const char *name; @@ -78,3 +82,25 @@ const char *get_arch_regstr(unsigned int n) return roff->name; return NULL; } + +#ifdef HAVE_BPF_PROLOGUE +int arch_get_reg_info(const char *name, int *offset) +{ + const struct pt_regs_dwarfnum *roff; + + if (!name || !offset) + return -1; + + for (roff = regdwarfnum_table; roff->name != NULL; roff++) { + if (!strcmp(roff->name, name)) { + if (roff->dwarfnum < 0) + return -1; + + *offset = roff->dwarfnum * PT_REG_SIZE; + return 0; + } + } + + return -1; +} +#endif -- 1.8.5.2 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH] perf tools: Support bpf prologue for arm64
Hi, Arnaldo On 2015/9/1 4:16, Arnaldo Carvalho de Melo wrote: Em Sat, Aug 29, 2015 at 03:16:52AM +, He Kuang escreveu: This patch implements arch_get_reg_info() for arm64 to enable HAVE_BPF_PROLOGUE feature. For arm64, structure pt_regs is not composed by fields of register names but an array of regs, so here we simply multiply fixed register size by index number to get the byte offset. Hi Jean, Will, are you ok with this? Can I have Acked-by or Reviewed-by tags from you? He, please try to add the authors of the files you change in the CC list. Ok, usually I use the get_maintainers.pl script, but it seems that the output do not include file authors: ./scripts/get_maintainer.pl 0001-perf-tools-Support-bpf-prologue-for-arm64.patch Peter Zijlstra (supporter:PERFORMANCE EVENTS SUBSYSTEM) Ingo Molnar (supporter:PERFORMANCE EVENTS SUBSYSTEM) Arnaldo Carvalho de Melo (supporter:PERFORMANCE EVENTS SUBSYSTEM,commit_signer:1/2=50%) Jiri Olsa (commit_signer:1/2=50%,authored:1/2=50%,removed_lines:4/4=100%) He Kuang (commit_signer:1/2=50%,authored:1/2=50%,added_lines:1/1=100%,commit_signer:1/1=100%,authored:1/1=100%,added_lines:23/23=100%) linux-kernel@vger.kernel.org (open list:PERFORMANCE EVENTS SUBSYSTEM) get_maintainers.pl bug? - Arnaldo Signed-off-by: He Kuang --- tools/perf/arch/arm64/Makefile | 1 + tools/perf/arch/arm64/util/dwarf-regs.c | 26 ++ 2 files changed, 27 insertions(+) diff --git a/tools/perf/arch/arm64/Makefile b/tools/perf/arch/arm64/Makefile index 7fbca17..1256e6e 100644 --- a/tools/perf/arch/arm64/Makefile +++ b/tools/perf/arch/arm64/Makefile @@ -1,3 +1,4 @@ ifndef NO_DWARF PERF_HAVE_DWARF_REGS := 1 endif +PERF_HAVE_ARCH_GET_REG_INFO := 1 diff --git a/tools/perf/arch/arm64/util/dwarf-regs.c b/tools/perf/arch/arm64/util/dwarf-regs.c index d49efeb..cb2c50a 100644 --- a/tools/perf/arch/arm64/util/dwarf-regs.c +++ b/tools/perf/arch/arm64/util/dwarf-regs.c @@ -10,6 +10,10 @@ #include #include +#include +#include + +#define PT_REG_SIZE (sizeof(((struct user_pt_regs *)0)->regs[0])) struct pt_regs_dwarfnum { const char *name; @@ -78,3 +82,25 @@ const char *get_arch_regstr(unsigned int n) return roff->name; return NULL; } + +#ifdef HAVE_BPF_PROLOGUE +int arch_get_reg_info(const char *name, int *offset) +{ + const struct pt_regs_dwarfnum *roff; + + if (!name || !offset) + return -1; + + for (roff = regdwarfnum_table; roff->name != NULL; roff++) { + if (!strcmp(roff->name, name)) { + if (roff->dwarfnum < 0) + return -1; Here's a compile error. error: comparison of unsigned expression < 0 is always false [-Werror=type-limits] So remove this useless comparison: --- tools/perf/arch/arm64/Makefile | 1 + tools/perf/arch/arm64/util/dwarf-regs.c | 23 +++ 2 files changed, 24 insertions(+) diff --git a/tools/perf/arch/arm64/Makefile b/tools/perf/arch/arm64/Makefile index 7fbca17..1256e6e 100644 --- a/tools/perf/arch/arm64/Makefile +++ b/tools/perf/arch/arm64/Makefile @@ -1,3 +1,4 @@ ifndef NO_DWARF PERF_HAVE_DWARF_REGS := 1 endif +PERF_HAVE_ARCH_GET_REG_INFO := 1 diff --git a/tools/perf/arch/arm64/util/dwarf-regs.c b/tools/perf/arch/arm64/util/dwarf-regs.c index d49efeb..cb935c4 100644 --- a/tools/perf/arch/arm64/util/dwarf-regs.c +++ b/tools/perf/arch/arm64/util/dwarf-regs.c @@ -10,6 +10,10 @@ #include #include +#include +#include + +#define PT_REG_SIZE (sizeof(((struct user_pt_regs *)0)->regs[0])) struct pt_regs_dwarfnum { const char *name; @@ -78,3 +82,22 @@ const char *get_arch_regstr(unsigned int n) return roff->name; return NULL; } + +#ifdef HAVE_BPF_PROLOGUE +int arch_get_reg_info(const char *name, int *offset) +{ + const struct pt_regs_dwarfnum *roff; + + if (!name || !offset) + return -1; + + for (roff = regdwarfnum_table; roff->name != NULL; roff++) { + if (!strcmp(roff->name, name)) { + *offset = roff->dwarfnum * PT_REG_SIZE; + return 0; + } + } + + return -1; +} +#endif -- 1.8.5.2 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [RFC PATCH 2/2] bpf: Implement bpf_perf_event_sample_enable/disable() helpers
hi, Alexei What about using similar implementation like PERF_EVENT_IOC_SET_OUTPUT, creating a new ioctl like PERF_EVENT_IOC_SET_ENABLER, then let perf to select an event as 'enabler', then BPF can still control one atomic variable to enable/disable a set of events. you lost me on that last sentence. How this 'enabler' will work? Also I'm still missing what's wrong with perf doing ioctl() on events on all cpus manually when bpf program tells it to do so. Is it speed you concerned about or extra work in perf ? For not having too much wakeups, perf ringbuffer has a watermark limit to cache events and reduce the wakeups, which causes perf userspace tool can not receive perf events immediately. Here's a simple demo expamle to prove it, 'sleep_exec' does some writes and prints a timestamp every second, and an lable is printed when perf poll gets events. $ perf record -m 2 -e syscalls:sys_enter_write sleep_exec 1000 userspace sleep time: 0 seconds userspace sleep time: 1 seconds userspace sleep time: 2 seconds userspace sleep time: 3 seconds perf record wakeup onetime 0 userspace sleep time: 4 seconds userspace sleep time: 5 seconds userspace sleep time: 6 seconds userspace sleep time: 7 seconds perf record wakeup onetime 1 userspace sleep time: 8 seconds perf record wakeup onetime 2 .. $ perf record -m 1 -e syscalls:sys_enter_write sleep_exec 1000 userspace sleep time: 0 seconds userspace sleep time: 1 seconds perf record wakeup onetime 0 userspace sleep time: 2 seconds userspace sleep time: 3 seconds perf record wakeup onetime 1 userspace sleep time: 4 seconds userspace sleep time: 5 seconds .. By default, if no mmap_pages is specified, perf tools wakeup only when the target executalbe finished: $ perf record -e syscalls:sys_enter_write sleep_exec 5 userspace sleep time: 0 seconds userspace sleep time: 1 seconds userspace sleep time: 2 seconds userspace sleep time: 3 seconds userspace sleep time: 4 seconds perf record wakeup onetime 0 [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.006 MB perf.data (54 samples) ] If we want perf to reflect as soon as our sample event be generated, --no-buffering should be used, but this option has a greater impact on performance. $ perf record --no-buffering -e syscalls:sys_enter_write sleep_exec 1000 userspace sleep time: 0 seconds perf record wakeup onetime 0 perf record wakeup onetime 1 perf record wakeup onetime 2 perf record wakeup onetime 3 perf record wakeup onetime 4 perf record wakeup onetime 5 perf record wakeup onetime 6 .. Thank you -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH net-next 2/3] bpf: introduce bpf_perf_event_output() helper
hi, Alexei I've tested the sample in next patch and it works well. I think more work on the perf side needs to be done for parsing PERF_COUNT_SW_BPF_OUTPUT event type, are you working on that? Thank you. On 2015/10/21 11:02, Alexei Starovoitov wrote: This helper is used to send raw data from eBPF program into special PERF_TYPE_SOFTWARE/PERF_COUNT_SW_BPF_OUTPUT perf_event. User space needs to perf_event_open() it (either for one or all cpus) and store FD into perf_event_array (similar to bpf_perf_event_read() helper) before eBPF program can send data into it. Today the programs triggered by kprobe collect the data and either store it into the maps or print it via bpf_trace_printk() where latter is the debug facility and not suitable to stream the data. This new helper replaces such bpf_trace_printk() usage and allows programs to have dedicated channel into user space for post-processing of the raw data collected. Signed-off-by: Alexei Starovoitov --- include/uapi/linux/bpf.h| 11 ++ include/uapi/linux/perf_event.h |1 + kernel/bpf/arraymap.c |2 ++ kernel/bpf/verifier.c |3 ++- kernel/trace/bpf_trace.c| 46 +++ 5 files changed, 62 insertions(+), 1 deletion(-) diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 564f1f091991..2e032426cfb7 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -287,6 +287,17 @@ enum bpf_func_id { * Return: realm if != 0 */ BPF_FUNC_get_route_realm, + + /** +* bpf_perf_event_output(ctx, map, index, data, size) - output perf raw sample +* @ctx: struct pt_regs* +* @map: pointer to perf_event_array map +* @index: index of event in the map +* @data: data on stack to be output as raw data +* @size: size of data +* Return: 0 on success +*/ + BPF_FUNC_perf_event_output, __BPF_FUNC_MAX_ID, }; diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_event.h index 2881145cda86..d3c417615361 100644 --- a/include/uapi/linux/perf_event.h +++ b/include/uapi/linux/perf_event.h @@ -110,6 +110,7 @@ enum perf_sw_ids { PERF_COUNT_SW_ALIGNMENT_FAULTS = 7, PERF_COUNT_SW_EMULATION_FAULTS = 8, PERF_COUNT_SW_DUMMY = 9, + PERF_COUNT_SW_BPF_OUTPUT= 10, PERF_COUNT_SW_MAX, /* non-ABI */ }; diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c index f2d9e698c753..e3cfe46b074f 100644 --- a/kernel/bpf/arraymap.c +++ b/kernel/bpf/arraymap.c @@ -295,6 +295,8 @@ static void *perf_event_fd_array_get_ptr(struct bpf_map *map, int fd) return (void *)attr; if (attr->type != PERF_TYPE_RAW && + !(attr->type == PERF_TYPE_SOFTWARE && + attr->config == PERF_COUNT_SW_BPF_OUTPUT) && attr->type != PERF_TYPE_HARDWARE) { perf_event_release_kernel(event); return ERR_PTR(-EINVAL); diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 1d6b97be79e1..b56cf51f8d42 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -245,6 +245,7 @@ static const struct { } func_limit[] = { {BPF_MAP_TYPE_PROG_ARRAY, BPF_FUNC_tail_call}, {BPF_MAP_TYPE_PERF_EVENT_ARRAY, BPF_FUNC_perf_event_read}, + {BPF_MAP_TYPE_PERF_EVENT_ARRAY, BPF_FUNC_perf_event_output}, }; static void print_verifier_state(struct verifier_env *env) @@ -910,7 +911,7 @@ static int check_map_func_compatibility(struct bpf_map *map, int func_id) * don't allow any other map type to be passed into * the special func; */ - if (bool_map != bool_func) + if (bool_func && bool_map != bool_func) return -EINVAL; } diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c index 0fe96c7c8803..47febbe7998e 100644 --- a/kernel/trace/bpf_trace.c +++ b/kernel/trace/bpf_trace.c @@ -215,6 +215,50 @@ const struct bpf_func_proto bpf_perf_event_read_proto = { .arg2_type = ARG_ANYTHING, }; +static u64 bpf_perf_event_output(u64 r1, u64 r2, u64 index, u64 r4, u64 size) +{ + struct pt_regs *regs = (struct pt_regs *) (long) r1; + struct bpf_map *map = (struct bpf_map *) (long) r2; + struct bpf_array *array = container_of(map, struct bpf_array, map); + void *data = (void *) (long) r4; + struct perf_sample_data sample_data; + struct perf_event *event; + struct perf_raw_record raw = { + .size = size, + .data = data, + }; + + if (unlikely(index >= array->map.max_entries)) + return -E2BIG; + + event = (struct perf_event *)array->ptrs[index]; + if (unlikely(!event)) + return -ENOENT; + + if (unlikely(event->attr.type != PERF_
Re: [RFC PATCH] bpf: Add new bpf map type for timer
ping and add a...@plumgrid.com, what's your opinion on this? On 2015/10/19 13:34, He Kuang wrote: This patch implements a timer map type inherited from array map. eBPF programs can deloy a timer by updating an entry in timer map, and destroy that by deleting the entry. The timer delay time(ns) is set by updating the value field of the entries. Currently, an intended empty function is called when the timer is triggered, then eBPF programs can be attatched to this function and perfrom customized functions. Signed-off-by: He Kuang --- Here's a hypothetical scenario to illustrate the use of timer map. A video frame is updated between frame_refresh_start() and frame_refresh_end(), in most cases, the interval between these two functions is less than 40ms, but occasionally over 200ms. We can set a timer which alarm after the frame_refresh_start() has been executed 42ms(slightly larger than 40ms) and destory this timer if frame_refresh_end() is called. So, for most cases, the timer is not triggered, this can significantly reduce the amount of trace data. eBPF progs: struct bpf_map_def SEC("maps") timer_map = { .type = BPF_MAP_TYPE_TIMER_ARRAY, .key_size = sizeof(int), .value_size = sizeof(unsigned long long), .max_entries = 4, }; SEC("func1=frame_refresh_start") int bpf_prog1(struct pt_regs *ctx) { int delay_ns = 42 * NSEC_PER_MSEC; /* 42 milliseconds */ unsigned int index = 0; bpf_map_update_elem(&timer_map, &index, &delay_ns, BPF_ANY); return 0; } SEC("func2=frame_refresh_end") int bpf_prog2(struct pt_regs *ctx) { unsigned int index = 0; bpf_map_delete_elem(&timer_map, &index); return 0; } SEC("func3=bpf_timer_callback") int bpf_prog3(struct pt_regs *ctx, int result) { char fmt[] = "timer triggered\n"; bpf_trace_printk(fmt, sizeof(fmt)); /* If comes here, frame refresh time is beyond the threshold we can switch on more tracepoints or enable more detailed trace paramaters to diagnose the problems. */ return 0; } Then we can write an exec to test the ebpf progs above, each timeout frame updates will trigger the timer. --- include/uapi/linux/bpf.h | 1 + kernel/bpf/arraymap.c| 161 +++ 2 files changed, 149 insertions(+), 13 deletions(-) diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 92a48e2..c41c80e 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -115,6 +115,7 @@ enum bpf_map_type { BPF_MAP_TYPE_ARRAY, BPF_MAP_TYPE_PROG_ARRAY, BPF_MAP_TYPE_PERF_EVENT_ARRAY, + BPF_MAP_TYPE_TIMER_ARRAY, }; enum bpf_prog_type { diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c index 29ace10..1e03c70 100644 --- a/kernel/bpf/arraymap.c +++ b/kernel/bpf/arraymap.c @@ -16,18 +16,10 @@ #include #include -/* Called from syscall */ -static struct bpf_map *array_map_alloc(union bpf_attr *attr) +static struct bpf_map *__array_map_alloc(union bpf_attr *attr, u32 elem_size) { struct bpf_array *array; - u32 elem_size, array_size; - - /* check sanity of attributes */ - if (attr->max_entries == 0 || attr->key_size != 4 || - attr->value_size == 0) - return ERR_PTR(-EINVAL); - - elem_size = round_up(attr->value_size, 8); + u32 array_size; /* check round_up into zero and u32 overflow */ if (elem_size == 0 || @@ -54,6 +46,20 @@ static struct bpf_map *array_map_alloc(union bpf_attr *attr) return &array->map; } +/* Called from syscall */ +static struct bpf_map *array_map_alloc(union bpf_attr *attr) +{ + u32 elem_size; + + /* check sanity of attributes */ + if (attr->max_entries == 0 || attr->key_size != 4 || + attr->value_size == 0) + return ERR_PTR(-EINVAL); + + elem_size = round_up(attr->value_size, 8); + return __array_map_alloc(attr, elem_size); +} + /* Called from syscall or from eBPF program */ static void *array_map_lookup_elem(struct bpf_map *map, void *key) { @@ -171,7 +177,7 @@ static void fd_array_map_free(struct bpf_map *map) kvfree(array); } -static void *fd_array_map_lookup_elem(struct bpf_map *map, void *key) +static void *empty_array_map_lookup_elem(struct bpf_map *map, void *key) { return NULL; } @@ -255,7 +261,7 @@ static const struct bpf_map_ops prog_array_ops = { .map_alloc = fd_array_map_alloc, .map_free = fd_array_map_free, .map_get_next_key = array_map_get_next_key, - .map_lookup_elem = fd_array_map_lookup_elem, + .map_lookup_elem = empty_array_map_lookup_elem, .map_update_elem = fd_array_map_update_elem, .map_delete_elem = fd_array_map_de
[RFC PATCH] bpf: Add new bpf map type for timer
This patch implements a timer map type inherited from array map. eBPF programs can deloy a timer by updating an entry in timer map, and destroy that by deleting the entry. The timer delay time(ns) is set by updating the value field of the entries. Currently, an intended empty function is called when the timer is triggered, then eBPF programs can be attatched to this function and perfrom customized functions. Signed-off-by: He Kuang --- Here's a hypothetical scenario to illustrate the use of timer map. A video frame is updated between frame_refresh_start() and frame_refresh_end(), in most cases, the interval between these two functions is less than 40ms, but occasionally over 200ms. We can set a timer which alarm after the frame_refresh_start() has been executed 42ms(slightly larger than 40ms) and destory this timer if frame_refresh_end() is called. So, for most cases, the timer is not triggered, this can significantly reduce the amount of trace data. eBPF progs: struct bpf_map_def SEC("maps") timer_map = { .type = BPF_MAP_TYPE_TIMER_ARRAY, .key_size = sizeof(int), .value_size = sizeof(unsigned long long), .max_entries = 4, }; SEC("func1=frame_refresh_start") int bpf_prog1(struct pt_regs *ctx) { int delay_ns = 42 * NSEC_PER_MSEC; /* 42 milliseconds */ unsigned int index = 0; bpf_map_update_elem(&timer_map, &index, &delay_ns, BPF_ANY); return 0; } SEC("func2=frame_refresh_end") int bpf_prog2(struct pt_regs *ctx) { unsigned int index = 0; bpf_map_delete_elem(&timer_map, &index); return 0; } SEC("func3=bpf_timer_callback") int bpf_prog3(struct pt_regs *ctx, int result) { char fmt[] = "timer triggered\n"; bpf_trace_printk(fmt, sizeof(fmt)); /* If comes here, frame refresh time is beyond the threshold we can switch on more tracepoints or enable more detailed trace paramaters to diagnose the problems. */ return 0; } Then we can write an exec to test the ebpf progs above, each timeout frame updates will trigger the timer. --- include/uapi/linux/bpf.h | 1 + kernel/bpf/arraymap.c| 161 +++ 2 files changed, 149 insertions(+), 13 deletions(-) diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 92a48e2..c41c80e 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -115,6 +115,7 @@ enum bpf_map_type { BPF_MAP_TYPE_ARRAY, BPF_MAP_TYPE_PROG_ARRAY, BPF_MAP_TYPE_PERF_EVENT_ARRAY, + BPF_MAP_TYPE_TIMER_ARRAY, }; enum bpf_prog_type { diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c index 29ace10..1e03c70 100644 --- a/kernel/bpf/arraymap.c +++ b/kernel/bpf/arraymap.c @@ -16,18 +16,10 @@ #include #include -/* Called from syscall */ -static struct bpf_map *array_map_alloc(union bpf_attr *attr) +static struct bpf_map *__array_map_alloc(union bpf_attr *attr, u32 elem_size) { struct bpf_array *array; - u32 elem_size, array_size; - - /* check sanity of attributes */ - if (attr->max_entries == 0 || attr->key_size != 4 || - attr->value_size == 0) - return ERR_PTR(-EINVAL); - - elem_size = round_up(attr->value_size, 8); + u32 array_size; /* check round_up into zero and u32 overflow */ if (elem_size == 0 || @@ -54,6 +46,20 @@ static struct bpf_map *array_map_alloc(union bpf_attr *attr) return &array->map; } +/* Called from syscall */ +static struct bpf_map *array_map_alloc(union bpf_attr *attr) +{ + u32 elem_size; + + /* check sanity of attributes */ + if (attr->max_entries == 0 || attr->key_size != 4 || + attr->value_size == 0) + return ERR_PTR(-EINVAL); + + elem_size = round_up(attr->value_size, 8); + return __array_map_alloc(attr, elem_size); +} + /* Called from syscall or from eBPF program */ static void *array_map_lookup_elem(struct bpf_map *map, void *key) { @@ -171,7 +177,7 @@ static void fd_array_map_free(struct bpf_map *map) kvfree(array); } -static void *fd_array_map_lookup_elem(struct bpf_map *map, void *key) +static void *empty_array_map_lookup_elem(struct bpf_map *map, void *key) { return NULL; } @@ -255,7 +261,7 @@ static const struct bpf_map_ops prog_array_ops = { .map_alloc = fd_array_map_alloc, .map_free = fd_array_map_free, .map_get_next_key = array_map_get_next_key, - .map_lookup_elem = fd_array_map_lookup_elem, + .map_lookup_elem = empty_array_map_lookup_elem, .map_update_elem = fd_array_map_update_elem, .map_delete_elem = fd_array_map_delete_elem, .map_fd_get_ptr = prog_fd_array_get_ptr, @@ -312,7 +318,7 @@ static const struct bpf_map_ops perf_
[PATCHv2] perf probe: Fix failure to add multiple probes without debuginfo
Perf tries to find probe function addresses from map when debuginfo could not be found. To the first added function, the value of ref_reloc_sym was set in maps__set_kallsyms_ref_reloc_sym() and can be obtained from host_machine->kmaps->maps. After that, new maps are added to host_machine->kmaps->maps in dso__load_kcore(), all these new added maps do not have a valid ref_reloc_sym. When adding a second function, get_target_map() may get a map without valid ref_reloc_sym, and raise the error "Relocated base symbol is not found". Fix this by using kernel_get_ref_reloc_sym() to get ref_reloc_sym. This problem can be reproduced as following: $ perf probe --add='sys_write' --add='sys_open' Relocated base symbol is not found! Error: Failed to add events. After this patch: $ perf probe --add='sys_write' --add='sys_open' Added new event: probe:sys_write (on sys_write) You can now use it in all perf tools, such as: perf record -e probe:sys_write -aR sleep 1 Added new event: probe:sys_open (on sys_open) You can now use it in all perf tools, such as: perf record -e probe:sys_open -aR sleep 1 Signed-off-by: He Kuang --- tools/perf/util/probe-event.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index c5e1338..c1ccd6a 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -2507,7 +2507,6 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev, int max_tevs, const char *target) { struct map *map = NULL; - struct kmap *kmap = NULL; struct ref_reloc_sym *reloc_sym = NULL; struct symbol *sym; struct probe_trace_event *tev; @@ -2540,8 +2539,7 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev, } if (!pev->uprobes && !pp->retprobe) { - kmap = map__kmap(map); - reloc_sym = kmap->ref_reloc_sym; + reloc_sym = kernel_get_ref_reloc_sym(); if (!reloc_sym) { pr_warning("Relocated base symbol is not found!\n"); ret = -EINVAL; -- 2.3.3.220.g9ab698f -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 2/2] perf trace: Fix segmentfault on perf trace
After perf_evlist__filter_pollfd() filters out fds and releases perf_mmap by using perf_evlist__mmap_put(), refcnt of perf_mmap hits 1 then perf_evlist__mmap_consume() will do the final unmap. In this condition, perf_evlist__mmap_read() will crash by referencing invalid mmap. Put refcnt check before use. Can be reproduced as following: $ perf trace --duration 1.0 ls ... perf: Segmentation fault Obtained 14 stack frames. ./perf(dump_stack+0x2e) [0x503c2d] ./perf(sighandler_dump_stack+0x2e) [0x503d0c] /lib64/libc.so.6(+0x34df0) [0x7f5fd9a4adf0] ./perf() [0x4a8fda] ./perf(perf_evlist__mmap_read+0x56) [0x4aae93] ./perf() [0x470b28] ./perf(cmd_trace+0xada) [0x4727bd] ./perf() [0x49c4f4] ./perf() [0x49c74d] ./perf() [0x49c899] ./perf(main+0x23b) [0x49cbfa] /lib64/libc.so.6(__libc_start_main+0xf5) [0x7f5fd9a377b5] ./perf() [0x434ea5] [(nil)] Signed-off-by: He Kuang --- tools/perf/util/evlist.c | 13 ++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 76ef7ee..9d36433 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -634,11 +634,18 @@ static struct perf_evsel *perf_evlist__event2evsel(struct perf_evlist *evlist, union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx) { struct perf_mmap *md = &evlist->mmap[idx]; - unsigned int head = perf_mmap__read_head(md); - unsigned int old = md->prev; - unsigned char *data = md->base + page_size; + unsigned int head; + unsigned int old; + unsigned char *data; union perf_event *event = NULL; + if (md == NULL || md->refcnt == 0) + return NULL; + + head = perf_mmap__read_head(md); + old = md->prev; + data = md->base + page_size; + if (evlist->overwrite) { /* * If we're further behind than half the buffer, there's a chance -- 2.3.3.220.g9ab698f -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 1/2] perf evlist: Fix inverted logic in perf_mmap__empty
perf_evlist__mmap_consume() uses perf_mmap__empty() to judge whether perf_mmap is empty and can be released. But the result is inverted so fix it. Signed-off-by: He Kuang --- tools/perf/util/evlist.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 82bf224..76ef7ee 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -695,7 +695,7 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx) static bool perf_mmap__empty(struct perf_mmap *md) { - return perf_mmap__read_head(md) != md->prev; + return perf_mmap__read_head(md) == md->prev; } static void perf_evlist__mmap_get(struct perf_evlist *evlist, int idx) -- 2.3.3.220.g9ab698f -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH] perf probe: Fix bug in perf probe with global variables
There are missing curly braces which causes find_variable() return wrong value when probing with global variables. This problem can be reproduced as following: $ perf probe -v --add='generic_perform_write global_variable_for_test' ... Try to find probe point from debuginfo. Probe point found: generic_perform_write+0 Searching 'global_variable_for_test' variable in context. An error occurred in debuginfo analysis (-2). Error: Failed to add events. Reason: No such file or directory (Code: -2) After this patch: $ perf probe -v --add='generic_perform_write global_variable_for_test' ... Converting variable global_variable_for_test into trace event. global_variable_for_test type is int. Found 1 probe_trace_events. Opening /sys/kernel/debug/tracing/kprobe_events write=1 Added new event: Writing event: p:probe/generic_perform_write _stext+1237464 global_variable_for_test=@global_variable_for_test+0:s32 probe:generic_perform_write (on generic_perform_write with global_variable_for_test) You can now use it in all perf tools, such as: perf record -e probe:generic_perform_write -aR sleep 1 Signed-off-by: He Kuang --- tools/perf/util/probe-finder.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index 44554c3..1c3cc07 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c @@ -578,10 +578,12 @@ static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf) /* Search child die for local variables and parameters. */ if (!die_find_variable_at(sc_die, pf->pvar->var, pf->addr, &vr_die)) { /* Search again in global variables */ - if (!die_find_variable_at(&pf->cu_die, pf->pvar->var, 0, &vr_die)) + if (!die_find_variable_at(&pf->cu_die, pf->pvar->var, + 0, &vr_die)) { pr_warning("Failed to find '%s' in this function.\n", pf->pvar->var); ret = -ENOENT; + } } if (ret >= 0) ret = convert_variable(&vr_die, pf); -- 1.8.5.2 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH 2/2] perf trace: Fix segmentfault on perf trace
Hi, Arnaldo On 2015/4/7 20:36, Arnaldo Carvalho de Melo wrote: Em Tue, Apr 07, 2015 at 05:31:11PM +0800, He Kuang escreveu: After perf_evlist__filter_pollfd() filters out fds and releases perf_mmap by using perf_evlist__mmap_put(), refcnt of perf_mmap hits 1 then perf_evlist__mmap_consume() will do the final unmap. In this condition, perf_evlist__mmap_read() will crash by referencing invalid mmap. Put refcnt check before use. Can be reproduced as following: After applying 1/2 in this series and trying to reproduce I couldn't, it works, looking at the code... Let me get my head around this, idea was that after all fds associated with a mmap would be closed, i.e. the perf_mmap->refcnt hits zero, then we would have to drain whatever was left in the mmap, but looking again that doesn't look like that is what is doing, becaue in filter_pollfd we will munmap it before being able to "drain" it, as all mmaps were closed, thus filter_pollfd returned zero... In function __perf_evlist__mmap(), refcnt is initialized to 2, see commit: 823969860329 ("perf evlist: Refcount mmaps") After filter_pollfd, perf_mmap->refcnt is 1 not 0. perf_evlist__filter_pollfd() -- refcnt=1 draining = true if (perf_evlist__mmap_read() != NULL) perf_evlist__mmap_consume()-- unmap, refcnt = 0 perf_evlist__mmap_read()-- segfault else exit I noticed that this issue also exists in builtin-record.c, but it checks before mmap_read(): if (rec->evlist->mmap[i].base) { if (record__mmap_read(rec, i, draining) != 0) { So we can either do the check outside builtin-trace.c:perf_evlist__mmap_read() like what builtin-record.c do or inside. What's your opinion? Reading on, thanks for the patch! - Arnaldo $ perf trace --duration 1.0 ls ... perf: Segmentation fault Obtained 14 stack frames. ./perf(dump_stack+0x2e) [0x503c2d] ./perf(sighandler_dump_stack+0x2e) [0x503d0c] /lib64/libc.so.6(+0x34df0) [0x7f5fd9a4adf0] ./perf() [0x4a8fda] ./perf(perf_evlist__mmap_read+0x56) [0x4aae93] ./perf() [0x470b28] ./perf(cmd_trace+0xada) [0x4727bd] ./perf() [0x49c4f4] ./perf() [0x49c74d] ./perf() [0x49c899] ./perf(main+0x23b) [0x49cbfa] /lib64/libc.so.6(__libc_start_main+0xf5) [0x7f5fd9a377b5] ./perf() [0x434ea5] [(nil)] Signed-off-by: He Kuang --- tools/perf/util/evlist.c | 13 ++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 76ef7ee..9d36433 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -634,11 +634,18 @@ static struct perf_evsel *perf_evlist__event2evsel(struct perf_evlist *evlist, union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx) { struct perf_mmap *md = &evlist->mmap[idx]; - unsigned int head = perf_mmap__read_head(md); - unsigned int old = md->prev; - unsigned char *data = md->base + page_size; + unsigned int head; + unsigned int old; + unsigned char *data; union perf_event *event = NULL; + if (md == NULL || md->refcnt == 0) + return NULL; + + head = perf_mmap__read_head(md); + old = md->prev; + data = md->base + page_size; + if (evlist->overwrite) { /* * If we're further behind than half the buffer, there's a chance -- 2.3.3.220.g9ab698f -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 2/2] perf data: Fix ctf_writer setupenv failure
Due to babeltrace commit: 7f800dc7c2a1 ("ir: make trace environment use bt_object") The trace->frozen flag is set in bt_ctf_trace_create_stream(), this flag is checked before adding environment field to trace, and causes ctf_writer__setup_env() failed. Fix this by setting all environment fields before bt_ctf_trace_create_stream(). Before this patch: $ perf data convert --to-ctf=ctf Error during CTF convert setup. After this patch: $ perf data convert --to-ctf=ctf [ perf data convert: Converted 'perf.data' into CTF data 'ctf' ] [ perf data convert: Converted and wrote 0.023 MB (596 samples) ] Signed-off-by: He Kuang --- tools/perf/util/data-convert-bt.c | 30 -- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/tools/perf/util/data-convert-bt.c b/tools/perf/util/data-convert-bt.c index a5b89b9..718dc8a 100644 --- a/tools/perf/util/data-convert-bt.c +++ b/tools/perf/util/data-convert-bt.c @@ -604,6 +604,22 @@ static int setup_events(struct ctf_writer *cw, struct perf_session *session) return 0; } +static int ctf_writer__setup_stream(struct ctf_writer *cw) +{ + struct bt_ctf_stream*stream; + + /* CTF stream instance */ + stream = bt_ctf_writer_create_stream(cw->writer, cw->stream_class); + if (!stream) { + pr("Failed to create CTF stream.\n"); + return -1; + } + + cw->stream = stream; + + return 0; +} + static int ctf_writer__setup_env(struct ctf_writer *cw, struct perf_session *session) { @@ -725,7 +741,6 @@ static int ctf_writer__init(struct ctf_writer *cw, const char *path) { struct bt_ctf_writer*writer; struct bt_ctf_stream_class *stream_class; - struct bt_ctf_stream*stream; struct bt_ctf_clock *clock; /* CTF writer */ @@ -767,15 +782,6 @@ static int ctf_writer__init(struct ctf_writer *cw, const char *path) if (ctf_writer__init_data(cw)) goto err_cleanup; - /* CTF stream instance */ - stream = bt_ctf_writer_create_stream(writer, stream_class); - if (!stream) { - pr("Failed to create CTF stream.\n"); - goto err_cleanup; - } - - cw->stream = stream; - /* CTF clock writer setup */ if (bt_ctf_writer_add_clock(writer, clock)) { pr("Failed to assign CTF clock to writer.\n"); @@ -830,6 +836,10 @@ int bt_convert__perf2ctf(const char *input, const char *path, bool force) if (ctf_writer__setup_env(cw, session)) goto free_session; + /* CTF writer trace stream setup */ + if (ctf_writer__setup_stream(cw)) + goto free_session; + /* CTF events setup */ if (setup_events(cw, session)) goto free_session; -- 2.3.3.220.g9ab698f -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 1/2] perf data: Show error message when ctf setup failed
Show message when errors occurred during ctf conversion setup. Before this patch: $ ./perf data convert --to-ctf=ctf $ echo $? 255 After this patch: $ ./perf data convert --to-ctf=ctf Error during CTF convert setup. Signed-off-by: He Kuang --- tools/perf/util/data-convert-bt.c | 8 ++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/data-convert-bt.c b/tools/perf/util/data-convert-bt.c index dd17c9a..a5b89b9 100644 --- a/tools/perf/util/data-convert-bt.c +++ b/tools/perf/util/data-convert-bt.c @@ -847,11 +847,15 @@ int bt_convert__perf2ctf(const char *input, const char *path, bool force) (double) c.events_size / 1024.0 / 1024.0, c.events_count); - /* its all good */ -free_session: perf_session__delete(session); + ctf_writer__cleanup(cw); + + return err; +free_session: + perf_session__delete(session); free_writer: ctf_writer__cleanup(cw); + pr_err("Error during CTF convert setup.\n"); return err; } -- 2.3.3.220.g9ab698f -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH 2/2] perf data: Fix ctf_writer setupenv failure
On 2015/4/9 1:59, Jiri Olsa wrote: On Wed, Apr 08, 2015 at 12:49:20PM +0800, He Kuang wrote: Due to babeltrace commit: 7f800dc7c2a1 ("ir: make trace environment use bt_object") The trace->frozen flag is set in bt_ctf_trace_create_stream(), this flag is checked before adding environment field to trace, and causes ctf_writer__setup_env() failed. Fix this by setting all environment fields before bt_ctf_trace_create_stream(). Before this patch: $ perf data convert --to-ctf=ctf Error during CTF convert setup. have you tested with the latest babeltrace sources? this reminds me the bug they fixed recently, CCing Jeremie thanks, jirka Yes, the latest babeltrace commit id: dfdad2587b12d454e7235e01508a266d83e3e264 After this patch: $ perf data convert --to-ctf=ctf [ perf data convert: Converted 'perf.data' into CTF data 'ctf' ] [ perf data convert: Converted and wrote 0.023 MB (596 samples) ] Signed-off-by: He Kuang --- tools/perf/util/data-convert-bt.c | 30 -- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/tools/perf/util/data-convert-bt.c b/tools/perf/util/data-convert-bt.c index a5b89b9..718dc8a 100644 --- a/tools/perf/util/data-convert-bt.c +++ b/tools/perf/util/data-convert-bt.c @@ -604,6 +604,22 @@ static int setup_events(struct ctf_writer *cw, struct perf_session *session) return 0; } +static int ctf_writer__setup_stream(struct ctf_writer *cw) +{ + struct bt_ctf_stream*stream; + + /* CTF stream instance */ + stream = bt_ctf_writer_create_stream(cw->writer, cw->stream_class); + if (!stream) { + pr("Failed to create CTF stream.\n"); + return -1; + } + + cw->stream = stream; + + return 0; +} + static int ctf_writer__setup_env(struct ctf_writer *cw, struct perf_session *session) { @@ -725,7 +741,6 @@ static int ctf_writer__init(struct ctf_writer *cw, const char *path) { struct bt_ctf_writer*writer; struct bt_ctf_stream_class *stream_class; - struct bt_ctf_stream*stream; struct bt_ctf_clock *clock; /* CTF writer */ @@ -767,15 +782,6 @@ static int ctf_writer__init(struct ctf_writer *cw, const char *path) if (ctf_writer__init_data(cw)) goto err_cleanup; - /* CTF stream instance */ - stream = bt_ctf_writer_create_stream(writer, stream_class); - if (!stream) { - pr("Failed to create CTF stream.\n"); - goto err_cleanup; - } - - cw->stream = stream; - /* CTF clock writer setup */ if (bt_ctf_writer_add_clock(writer, clock)) { pr("Failed to assign CTF clock to writer.\n"); @@ -830,6 +836,10 @@ int bt_convert__perf2ctf(const char *input, const char *path, bool force) if (ctf_writer__setup_env(cw, session)) goto free_session; + /* CTF writer trace stream setup */ + if (ctf_writer__setup_stream(cw)) + goto free_session; + /* CTF events setup */ if (setup_events(cw, session)) goto free_session; -- 2.3.3.220.g9ab698f -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCHv2 1/2] perf data: Show error message when conversion failed
Show message when errors occurred during conversion setup and conversion process. Before this patch: $ ./perf data convert --to-ctf=ctf $ echo $? 255 After this patch: $ ./perf data convert --to-ctf=ctf Error during conversion setup. Signed-off-by: He Kuang --- tools/perf/util/data-convert-bt.c | 10 -- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/data-convert-bt.c b/tools/perf/util/data-convert-bt.c index 7a12047..de80ded 100644 --- a/tools/perf/util/data-convert-bt.c +++ b/tools/perf/util/data-convert-bt.c @@ -896,6 +896,8 @@ int bt_convert__perf2ctf(const char *input, const char *path, bool force) err = perf_session__process_events(session); if (!err) err = bt_ctf_stream_flush(cw->stream); + else + pr_err("Error during conversion.\n"); fprintf(stderr, "[ perf data convert: Converted '%s' into CTF data '%s' ]\n", @@ -906,11 +908,15 @@ int bt_convert__perf2ctf(const char *input, const char *path, bool force) (double) c.events_size / 1024.0 / 1024.0, c.events_count); - /* its all good */ -free_session: perf_session__delete(session); + ctf_writer__cleanup(cw); + return err; + +free_session: + perf_session__delete(session); free_writer: ctf_writer__cleanup(cw); + pr_err("Error during conversion setup.\n"); return err; } -- 2.3.3.220.g9ab698f -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH 1/2] perf data: Show error message when ctf setup failed
Hi, jirka On 2015/4/9 1:45, Jiri Olsa wrote: On Wed, Apr 08, 2015 at 12:49:19PM +0800, He Kuang wrote: Show message when errors occurred during ctf conversion setup. Before this patch: $ ./perf data convert --to-ctf=ctf $ echo $? 255 After this patch: $ ./perf data convert --to-ctf=ctf Error during CTF convert setup. so I have like 5 more patches from the original CTF set which I'm holding until all works with tracecompass: http://marc.info/?l=linux-kernel&m=142736197610573&w=2 Is it working for you? How do you test resulted CTF data? anyway the patch looks ok, just small nit below I tested by using babeltrace binary and it works. After receiving your reply, I test on the latest tracecompass. A folder named 'ctf' is showed instead of the expected file 'ctf-data', this folder only contains the raw metadata and perf-stream files but not analysed. Signed-off-by: He Kuang --- tools/perf/util/data-convert-bt.c | 8 ++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/data-convert-bt.c b/tools/perf/util/data-convert-bt.c index dd17c9a..a5b89b9 100644 --- a/tools/perf/util/data-convert-bt.c +++ b/tools/perf/util/data-convert-bt.c @@ -847,11 +847,15 @@ int bt_convert__perf2ctf(const char *input, const char *path, bool force) (double) c.events_size / 1024.0 / 1024.0, c.events_count); - /* its all good */ -free_session: perf_session__delete(session); + ctf_writer__cleanup(cw); + this leg can also fail due to: err = perf_session__process_events(session); if (!err) err = bt_ctf_stream_flush(cw->stream); so we might want to inform about that like: if (err) pr_err("Error during conversion.\n"); thanks, jirka + return err; +free_session: + perf_session__delete(session); free_writer: ctf_writer__cleanup(cw); + pr_err("Error during CTF convert setup.\n"); return err; } -- 2.3.3.220.g9ab698f -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 2/3] perf probe: Make --source avaiable when probe with lazy_line
Use get_real_path() to enable --source option when probe with lazy_line pattern. Before this patch: $ perf probe -s ./kernel_src/ -k ./vmlinux --add='fs/super.c;s->s_count=1;' Failed to open fs/super.c: No such file or directory Error: Failed to add events. After this patch: $ perf probe -s ./kernel_src/ -k ./vmlinux --add='fs/super.c;s->s_count=1;' Added new events: probe:_stext (on @fs/super.c) probe:_stext_1 (on @fs/super.c) ... Signed-off-by: He Kuang --- tools/perf/util/probe-event.c | 2 +- tools/perf/util/probe-event.h | 2 ++ tools/perf/util/probe-finder.c | 18 +++--- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 5483d98..35ee51a 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -661,7 +661,7 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev, * a newly allocated path on success. * Return 0 if file was found and readable, -errno otherwise. */ -static int get_real_path(const char *raw_path, const char *comp_dir, +int get_real_path(const char *raw_path, const char *comp_dir, char **new_path) { const char *prefix = symbol_conf.source_prefix; diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h index d6b7834..21809ea 100644 --- a/tools/perf/util/probe-event.h +++ b/tools/perf/util/probe-event.h @@ -135,6 +135,8 @@ extern int show_available_vars(struct perf_probe_event *pevs, int npevs, struct strfilter *filter, bool externs); extern int show_available_funcs(const char *module, struct strfilter *filter, bool user); +extern int get_real_path(const char *raw_path, const char *comp_dir, + char **new_path); /* Maximum index number of event-name postfix */ #define MAX_EVENT_INDEX1024 diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index 7831e2d..431c12d 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c @@ -791,11 +791,20 @@ static int find_lazy_match_lines(struct intlist *list, ssize_t len; int count = 0, linenum = 1; char sbuf[STRERR_BUFSIZE]; + char *realname = NULL; + int ret; - fp = fopen(fname, "r"); + ret = get_real_path(fname, NULL, &realname); + if (ret < 0) { + pr_warning("Failed to find source file %s.\n", fname); + return ret; + } + + fp = fopen(realname, "r"); if (!fp) { - pr_warning("Failed to open %s: %s\n", fname, + pr_warning("Failed to open %s: %s\n", realname, strerror_r(errno, sbuf, sizeof(sbuf))); + free(realname); return -errno; } @@ -817,7 +826,10 @@ static int find_lazy_match_lines(struct intlist *list, fclose(fp); if (count == 0) - pr_debug("No matched lines found in %s.\n", fname); + pr_debug("No matched lines found in %s.\n", realname); + + free(realname); + return count; } -- 2.3.3.220.g9ab698f -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 3/3] perf probe: Fix segfault when probe with lazy_line to file
The first argument passed to find_probe_point_lazy() should be CU die, which will be passed to die_walk_lines() when lazy_line matches. Currently, when we probe with lazy_line pattern to file without function name, NULL pointer is passed and causes a segment fault. Can be repoduced as following: $ perf probe -k vmlinux --add='fs/super.c;s->s_count=1;' [ 1958.984658] perf[1020]: segfault at 10 ip 7fc6e10d8c71 sp 7ffcbfaaf900 error 4 in libdw-0.161.so[7fc6e10ce000+34000] Segmentation fault After this patch: $ perf probe -k vmlinux --add='fs/super.c;s->s_count=1;' Added new event: probe:_stext (on @fs/super.c) You can now use it in all perf tools, such as: perf record -e probe:_stext -aR sleep 1 Signed-off-by: He Kuang --- tools/perf/util/probe-finder.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index 431c12d..e91101b 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c @@ -1067,7 +1067,7 @@ static int debuginfo__find_probes(struct debuginfo *dbg, if (pp->function) ret = find_probe_point_by_func(pf); else if (pp->lazy_line) - ret = find_probe_point_lazy(NULL, pf); + ret = find_probe_point_lazy(&pf->cu_die, pf); else { pf->lno = pp->line; ret = find_probe_point_by_line(pf); -- 2.3.3.220.g9ab698f -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 1/3] perf probe: Set retprobe flag when probe in address-based alternative mode
Perf probe misses to set retprobe flag back when falling back to address-based alternative mode. Can be reproduced as following: $ perf probe -v -k vmlinux --add='sys_write%return' ... Added new event: Writing event: p:probe/sys_write _stext+1584952 probe:sys_write (on sys_write%return) $ cat /sys/kernel/debug/tracing/kprobe_events p:probe/sys_write _stext+1584952 After this patch: $ perf probe -v -k vmlinux --add='sys_write%return' Added new event: Writing event: r:probe/sys_write SyS_write+0 probe:sys_write (on sys_write%return) $ cat /sys/kernel/debug/tracing/kprobe_events r:probe/sys_write SyS_write Signed-off-by: He Kuang --- tools/perf/util/probe-event.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 30545ce..5483d98 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -332,6 +332,7 @@ static int find_alternative_probe_point(struct debuginfo *dinfo, else { result->offset += pp->offset; result->line += pp->line; + result->retprobe = pp->retprobe; ret = 0; } -- 2.3.3.220.g9ab698f -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH 1/3] perf probe: Set retprobe flag when probe in address-based alternative mode
On 04/13/2015 10:39 PM, Arnaldo Carvalho de Melo wrote: Em Mon, Apr 13, 2015 at 07:41:28PM +0800, He Kuang escreveu: Perf probe misses to set retprobe flag back when falling back to address-based alternative mode. And when is that happens, can you explain? Because I tried to follow your instructions, but in my case it worked in the same way before and after your patch. Can you please provide more context for reviewing your patch? More details: [root]# perf probe -v -k vmlinux --add='sys_write%return' probe-definition(0): sys_write%return symbol:sys_write file:(null) line:0 offset:0 return:1 lazy:(null) 0 arguments Use vmlinux: vmlinux map_groups__set_modules_path_dir: cannot open /lib/modules/4.0.0-rc6+ dir Problems setting modules path maps, continuing anyway... Using vmlinux for symbols Open Debuginfo file: vmlinux >>>== Try to find probe point from debuginfo. Symbol sys_write address found : 811a8cf0 Probe point found: SyS_write+0 Found 1 probe_trace_events. Opening /sys/kernel/debug/tracing/kprobe_events write=1 Added new event: Writing event: p:probe/sys_write _stext+1739560 probe:sys_write (on sys_write%return) You can now use it in all perf tools, such as: perf record -e probe:sys_write -aR sleep 1 [root@buildroot tmp]# cat /sys/kernel/debug/tracing/kprobe_events p:probe/sys_write _stext+1739560 The line I marked is different from your result, which is: """Could not open debuginfo. Try to use symbols.""" When perf probe searched in debuginfo and failed, it tried with alternative, in function get_alternative_probe_event(): memcpy(tmp, &pev->point, sizeof(*tmp)); memset(&pev->point, 0, sizeof(pev->point)); In this case, it drops the retprobe flag and forgets to set it back in find_alternative_probe_point(), so the problem occurred. Here are my results: Before: [root@ssdandy ~]# perf probe -v --add='sys_write%return' probe-definition(0): sys_write%return symbol:sys_write file:(null) line:0 offset:0 return:1 lazy:(null) 0 arguments Using /root/.debug/.build-id/dd/32e51921ede0fd46f034091b7f6a0f2e01ebda for symbols Could not open debuginfo. Try to use symbols. Opening /sys/kernel/debug/tracing/kprobe_events write=1 Added new event: Writing event: r:probe/sys_write sys_write+0 probe:sys_write (on sys_write%return) You can now use it in all perf tools, such as: perf record -e probe:sys_write -aR sleep 1 [root@ssdandy ~]# cat /sys/kernel/debug/tracing/kprobe_events r:probe/sys_write sys_write Remove it: [root@ssdandy ~]# perf probe --del *:* Removed event: probe:sys_write After: [root@ssdandy ~]# perf probe -v --add='sys_write%return' probe-definition(0): sys_write%return symbol:sys_write file:(null) line:0 offset:0 return:1 lazy:(null) 0 arguments Using /root/.debug/.build-id/dd/32e51921ede0fd46f034091b7f6a0f2e01ebda for symbols Could not open debuginfo. Try to use symbols. Opening /sys/kernel/debug/tracing/kprobe_events write=1 Added new event: Writing event: r:probe/sys_write sys_write+0 probe:sys_write (on sys_write%return) You can now use it in all perf tools, such as: perf record -e probe:sys_write -aR sleep 1 [root@ssdandy ~]# [root@ssdandy ~]# cat /sys/kernel/debug/tracing/kprobe_events r:probe/sys_write sys_write Humm, noticed one other problem, but not with your patch, about this message: "Could not open debuginfo. Try to use symbols." That is really not clear, specially that "try to use symbols" :-) [root@ssdandy ~]# ls -la /root/.debug/.build-id/dd/32e51921ede0fd46f034091b7f6a0f2e01ebda lrwxrwxrwx. 1 root root 86 Apr 10 18:02 /root/.debug/.build-id/dd/32e51921ede0fd46f034091b7f6a0f2e01ebda -> ../../home/acme/git/build/v4.0.0-rc6+/vmlinux/dd32e51921ede0fd46f034091b7f6a0f2e01ebda [root@ssdandy ~]# ls -la /root/.debug/.build-id/dd/../../home/acme/git/build/v4.0.0-rc6+/vmlinux/dd32e51921ede0fd46f034091b7f6a0f2e01ebda -rwxr-xr-x. 1 root root 22698661 Apr 10 18:02 /root/.debug/.build-id/dd/../../home/acme/git/build/v4.0.0-rc6+/vmlinux/dd32e51921ede0fd46f034091b7f6a0f2e01ebda [root@ssdandy ~]# ls -la /root/.debug/.build-id/dd/../../home/acme/git/build/v4.0.0-rc6+/vmlinux/dd32e51921ede0fd46f034091b7f6a0f2e01ebda I.e. it managed to read the debuginfo, its just that it has no symbols in it :-) Anyway, digression ended. - Arnaldo Can be reproduced as following: $ perf probe -v -k vmlinux --add='sys_write%return' ... Added new event: Writing event: p:probe/sys_write _stext+1584952 probe:sys_write (on sys_write%return) $ cat /sys/kernel/debug/tracing/kprobe_events p:probe/sys_write _stext+1584952 After this patch: $ perf probe -v -k vmlinux --add='sys_write%return
Re: [PATCH 1/3] perf probe: Set retprobe flag when probe in address-based alternative mode
Hi, Arnaldo On 04/13/2015 10:42 PM, Arnaldo Carvalho de Melo wrote: Em Mon, Apr 13, 2015 at 11:39:03AM -0300, Arnaldo Carvalho de Melo escreveu: Em Mon, Apr 13, 2015 at 07:41:28PM +0800, He Kuang escreveu: Perf probe misses to set retprobe flag back when falling back to address-based alternative mode. Humm, noticed one other problem, but not with your patch, about this message: "Could not open debuginfo. Try to use symbols." That is really not clear, specially that "try to use symbols" :-) [root@ssdandy ~]# ls -la /root/.debug/.build-id/dd/32e51921ede0fd46f034091b7f6a0f2e01ebda lrwxrwxrwx. 1 root root 86 Apr 10 18:02 /root/.debug/.build-id/dd/32e51921ede0fd46f034091b7f6a0f2e01ebda -> ../../home/acme/git/build/v4.0.0-rc6+/vmlinux/dd32e51921ede0fd46f034091b7f6a0f2e01ebda [root@ssdandy ~]# ls -la /root/.debug/.build-id/dd/../../home/acme/git/build/v4.0.0-rc6+/vmlinux/dd32e51921ede0fd46f034091b7f6a0f2e01ebda -rwxr-xr-x. 1 root root 22698661 Apr 10 18:02 /root/.debug/.build-id/dd/../../home/acme/git/build/v4.0.0-rc6+/vmlinux/dd32e51921ede0fd46f034091b7f6a0f2e01ebda [root@ssdandy ~]# ls -la /root/.debug/.build-id/dd/../../home/acme/git/build/v4.0.0-rc6+/vmlinux/dd32e51921ede0fd46f034091b7f6a0f2e01ebda I.e. it managed to read the debuginfo, its just that it has no symbols in it :-) Anyway, digression ended. Interesting is that when testing your next patch I see: [root@ssdandy linux]# perf probe -s ./kernel_src/ --add='fs/super.c;s->s_count=1;' The /root/.debug/.build-id/dd/32e51921ede0fd46f034091b7f6a0f2e01ebda file has no debug information. Rebuild with CONFIG_DEBUG_INFO=y, or install an appropriate debuginfo package. Error: Failed to add events. [root@ssdandy linux]# Much, much clear message about that debuginfo file :-) But then, to test your [2/3] patch I'll have to figure out how to setup the environment so that I can match your results, shouldn't be hard, but would save reviewing time if you stated it in the commit log message. Sorry for not providing enough information. -s ./kernel_src/ The kernel_src dir is a kernel source tree path, it can be anywhere, for test you can only put fs/super.c in it: kernel_src/ -- fs -- super.c -k vmlinux This is necessary and should be matched to your running kernel. - Arnaldo -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/ -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [RFC PATCH v2 09/15] perf probe: Support $params without debuginfo
hi, Alexei On 2015/5/27 1:50, Alexei Starovoitov wrote: > On 5/25/15 1:33 AM, He Kuang wrote: >> Right, I learnt regparm(3) is mandatory in x86_32, according to rules, >> the first three args will go to regparm(ax, dx, cx). But we should not >> refer arg1~3 to ax, dx, cx because of 64bit parameters (other reasons?). >> >> Consider this keyword is used for generating bpf prologue which fetches >> formal parameters when no debuginfo is provided, for this purpose, we can: >> 1) We just help fetch the $regs or $regparms(If the keyword is >> $regparms, ax/dx/cx is fetched, nothing related to args) to bpf arglists >> and leave the rest things to bpf prog writer. >> >> 2) Keep that on platforms like x86_64 and skip this feature on >> platforms like x86_32. >> >> or any other suggestions? > > Single argument like $regparam or whatever name cannot work on all > architectures, that's why in the very beginning I suggested > 'func(long, char, void*)' syntax to describe arguments when debuginfo > is not available. Calling convention for scalars is simple enough on > all major architectures. x64_64 - trivial, i64_32 - a bit more involved, > but simple enough so that list of types of arguments is enough to figure > out which register or register pair or stack should be used to fetch > argN. > > As Masami has reminded, the use of 'asmlinkage' forces regparm=0, and we can't destinguish them without debuginfo, so 'func(long, char, void*)' syntax not work in everywhere. In fact, all the context infos are there in bpf prog(pt_regs in arg1). To the non-debuginfo case, without the help of prologue, user steps following flow to fetch params: 1. pt_regs(arg1) + architecture => calling regs 2. calling regs + function prototype(SEC) + gcc attributes(like asmlinkage) => formal parameters '$regparms' do the 1st step, though not a full workaround. But for the lack of gcc attributes, it seems we can't do the 2nd step. Any ideas? Thanks -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [RFC PATCH v2 09/15] perf probe: Support $params without debuginfo
On 2015/5/27 23:30, Alexei Starovoitov wrote: > On 5/26/15 7:27 PM, He Kuang wrote: >> hi, Alexei >> >> On 2015/5/27 1:50, Alexei Starovoitov wrote: >>> On 5/25/15 1:33 AM, He Kuang wrote: >>>> Right, I learnt regparm(3) is mandatory in x86_32, according to rules, >>>> the first three args will go to regparm(ax, dx, cx). But we should not >>>> refer arg1~3 to ax, dx, cx because of 64bit parameters (other reasons?). >>>> >>>> Consider this keyword is used for generating bpf prologue which fetches >>>> formal parameters when no debuginfo is provided, for this purpose, we can: >>>>1) We just help fetch the $regs or $regparms(If the keyword is >>>> $regparms, ax/dx/cx is fetched, nothing related to args) to bpf arglists >>>> and leave the rest things to bpf prog writer. >>>> >>>>2) Keep that on platforms like x86_64 and skip this feature on >>>> platforms like x86_32. >>>> >>>> or any other suggestions? >>> >>> Single argument like $regparam or whatever name cannot work on all >>> architectures, that's why in the very beginning I suggested >>> 'func(long, char, void*)' syntax to describe arguments when debuginfo >>> is not available. Calling convention for scalars is simple enough on >>> all major architectures. x64_64 - trivial, i64_32 - a bit more involved, >>> but simple enough so that list of types of arguments is enough to figure >>> out which register or register pair or stack should be used to fetch >>> argN. >>> >>> >> As Masami has reminded, the use of 'asmlinkage' forces regparm=0, and >> we can't destinguish them without debuginfo, so 'func(long, char, >> void*)' syntax not work in everywhere. >> >> In fact, all the context infos are there in bpf prog(pt_regs in arg1). >> To the non-debuginfo case, without the help of prologue, user steps >> following flow to fetch params: >> >> 1. pt_regs(arg1) + architecture => calling regs >> >> 2. calling regs + function prototype(SEC) + gcc attributes(like >> asmlinkage) => formal parameters >> >>'$regparms' do the 1st step, though not a full workaround. But for the >> lack of gcc attributes, it seems we can't do the 2nd step. Any ideas? > > I don't think you can break it down in two steps like this. > There is no such thing as 'calling regs'. x86_32 with ax,dx,cx > are not 'calling regs'. 64-bit values will be passed in a pair. > Only 'pt_regs + arch + func_proto + asmlinkage' makes sense > from the user point of view. > Adding 'asmlinkage' attr is also trivial. > 'func(long, char) asmlinkage' is easy to parse and the user I think at this early stage, we could make our bpf variable prologue work with debuginfo while keeping bpf 'SEC' syntax consistent with original perf probe. After all, we can use pt_regs directly or relay to perf-probe cache by Masami to deal with non-debug cases. > will be able to write programs that are architecture independent. > We already have 'struct pt_regs *' and $regparams don't buy us > anything extra. It may be useful for generic kprobe, but not for bpf. > > -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH] perf record: Fix perf.data size in no-buildid mode
The size of perf.data is missing update in no-buildid mode, which gives wrong output result. Before this patch: $ perf.perf record -B -e syscalls:sys_enter_open uname Linux [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.000 MB perf.data ] After this patch: $ perf.perf record -B -e syscalls:sys_enter_open uname Linux [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.001 MB perf.data ] Signed-off-by: He Kuang --- tools/perf/builtin-record.c | 6 ++ 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 91aa2a3..d3731cc 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -345,12 +345,9 @@ static int process_buildids(struct record *rec) struct perf_data_file *file = &rec->file; struct perf_session *session = rec->session; - u64 size = lseek(perf_data_file__fd(file), 0, SEEK_CUR); - if (size == 0) + if (file->size == 0) return 0; - file->size = size; - /* * During this process, it'll load kernel map and replace the * dso->long_name to a real pathname it found. In this case @@ -719,6 +716,7 @@ out_child: if (!err && !file->is_pipe) { rec->session->header.data_size += rec->bytes_written; + file->size = lseek(perf_data_file__fd(file), 0, SEEK_CUR); if (!rec->no_buildid) { process_buildids(rec); -- 1.8.5.2 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH RESEND 2/2] tools lib traceevent: Ignore libtrace-dynamic-list file
The libtrace-dynamic-list file is used to export symbols used by traceevent plugins. Signed-off-by: He Kuang --- tools/lib/traceevent/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/lib/traceevent/.gitignore b/tools/lib/traceevent/.gitignore index 35f56be..3c60335 100644 --- a/tools/lib/traceevent/.gitignore +++ b/tools/lib/traceevent/.gitignore @@ -1 +1,2 @@ TRACEEVENT-CFLAGS +libtraceevent-dynamic-list -- 1.8.5.2 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH RESEND 1/2] tools lib traceevent: Export dynamic symbols used by traceevent plugins
Traceevent plugins need dynamic symbols exported from libtraceevent.a, otherwise a dlopen error will occur during plugins loading. This patch uses dynamic-list-file to export dynamic symbols which will be used in plugins to perf executable. The problem is covered up if feature-libpython is enabled, because PYTHON_EMBED_LDOPTS contains '-Xlinker --export-dynamic' which adds all symbols to the dynamic symbol table. So we should reproduce the problem by setting NO_LIBPYTHON=1. Before this patch: (Prepare plugins) $ ls /root/.traceevent/plugins/ plugin_sched_switch.so plugin_function.so ... $ perf record -e 'ftrace:function' ls $ perf script Warning: could not load plugin '/mnt/data/root/.traceevent/plugins/plugin_sched_switch.so' /root/.traceevent/plugins/plugin_sched_switch.so: undefined symbol: pevent_unregister_event_handler Warning: could not load plugin '/root/.traceevent/plugins/plugin_function.so' /root/.traceevent/plugins/plugin_function.so: undefined symbol: warning ... :1049 1049 [000] 9666.754487: ftrace:function: 8118bc50 <-- 8118c5b3 :1049 1049 [000] 9666.754487: ftrace:function: 818e2440 <-- 8118bc75 :1049 1049 [000] 9666.754487: ftrace:function: 8106eee0 <-- 811212e2 After this patch: $ perf record -e 'ftrace:function' ls $ perf script :1049 1049 [000] 9666.754487: ftrace:function: __set_task_comm :1049 1049 [000] 9666.754487: ftrace:function:_raw_spin_lock :1049 1049 [000] 9666.754487: ftrace:function: task_tgid_nr_ns ... Signed-off-by: He Kuang Acked-by: Jiri Olsa --- tools/lib/traceevent/Makefile | 14 +- tools/perf/Makefile.perf | 14 -- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/tools/lib/traceevent/Makefile b/tools/lib/traceevent/Makefile index 8464039..6daaff6 100644 --- a/tools/lib/traceevent/Makefile +++ b/tools/lib/traceevent/Makefile @@ -23,6 +23,7 @@ endef # Allow setting CC and AR, or setting CROSS_COMPILE as a prefix. $(call allow-override,CC,$(CROSS_COMPILE)gcc) $(call allow-override,AR,$(CROSS_COMPILE)ar) +$(call allow-override,NM,$(CROSS_COMPILE)nm) EXT = -std=gnu99 INSTALL = install @@ -157,8 +158,9 @@ PLUGINS_IN := $(PLUGINS:.so=-in.o) TE_IN:= $(OUTPUT)libtraceevent-in.o LIB_FILE := $(addprefix $(OUTPUT),$(LIB_FILE)) +DYNAMIC_LIST_FILE := $(OUTPUT)libtraceevent-dynamic-list -CMD_TARGETS = $(LIB_FILE) $(PLUGINS) +CMD_TARGETS = $(LIB_FILE) $(PLUGINS) $(DYNAMIC_LIST_FILE) TARGETS = $(CMD_TARGETS) @@ -175,6 +177,9 @@ $(OUTPUT)libtraceevent.so: $(TE_IN) $(OUTPUT)libtraceevent.a: $(TE_IN) $(QUIET_LINK)$(RM) $@; $(AR) rcs $@ $^ +$(OUTPUT)libtraceevent-dynamic-list: $(PLUGINS) + $(QUIET_GEN)$(call do_generate_dynamic_list_file, $(PLUGINS), $@) + plugins: $(PLUGINS) __plugin_obj = $(notdir $@) @@ -244,6 +249,13 @@ define do_install_plugins done endef +define do_generate_dynamic_list_file + (echo '{'; \ + $(NM) -u -D $1 | awk 'NF>1 {print "\t"$$2";"}' | sort -u; \ + echo '};'; \ + ) > $2 +endef + install_lib: all_cmd install_plugins $(call QUIET_INSTALL, $(LIB_FILE)) \ $(call do_install,$(LIB_FILE),$(libdir_SQ)) diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 5816a3b..b1dfcd8 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -173,6 +173,9 @@ endif LIBTRACEEVENT = $(TE_PATH)libtraceevent.a export LIBTRACEEVENT +LIBTRACEEVENT_DYNAMIC_LIST = $(TE_PATH)libtraceevent-dynamic-list +LDFLAGS += -Xlinker --dynamic-list=$(LIBTRACEEVENT_DYNAMIC_LIST) + LIBAPI = $(LIB_PATH)libapi.a export LIBAPI @@ -278,7 +281,7 @@ build := -f $(srctree)/tools/build/Makefile.build dir=. obj $(PERF_IN): $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h FORCE $(Q)$(MAKE) $(build)=perf -$(OUTPUT)perf: $(PERFLIBS) $(PERF_IN) +$(OUTPUT)perf: $(PERFLIBS) $(PERF_IN) $(LIBTRACEEVENT_DYNAMIC_LIST) $(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $(PERF_IN) $(LIBS) -o $@ $(GTK_IN): FORCE @@ -373,7 +376,13 @@ $(LIB_FILE): $(LIBPERF_IN) LIBTRACEEVENT_FLAGS += plugin_dir=$(plugindir_SQ) $(LIBTRACEEVENT): FORCE - $(Q)$(MAKE) -C $(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) O=$(OUTPUT) $(OUTPUT)libtraceevent.a plugins + $(Q)$(MAKE) -C $(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) O=$(OUTPUT) $(OUTPUT)libtraceevent.a + +libtraceevent_plugins: FORCE + $(Q)$(MAKE) -C $(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) O=$(OUTPUT) plugins + +$(LIBTRACEEVENT_DYNAMIC_LIST): libtraceevent_plugins + $(Q)$(MAKE) -C $(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) O=$(OUTPUT) $(OUTPUT)libtrac
Re: [RFC PATCH v2 09/15] perf probe: Support $params without debuginfo
hi, Alexei On 2015/5/29 2:10, Alexei Starovoitov wrote: > On 5/28/15 6:01 AM, He Kuang wrote: >>> I don't think you can break it down in two steps like this. >>>> There is no such thing as 'calling regs'. x86_32 with ax,dx,cx >>>> are not 'calling regs'. 64-bit values will be passed in a pair. >>>> Only 'pt_regs + arch + func_proto + asmlinkage' makes sense >>> >from the user point of view. >>>> Adding 'asmlinkage' attr is also trivial. >>>> 'func(long, char) asmlinkage' is easy to parse and the user >> I think at this early stage, we could make our bpf variable >> prologue work with debuginfo while keeping bpf 'SEC' syntax >> consistent with original perf probe. After all, we can use >> pt_regs directly or relay to perf-probe cache by Masami to deal >> with non-debug cases. > > so you're saying you don't want to support non-debug case for now? > Sure, as long as section name parser will be able to support > 'func(long, char) asmlinkage' syntax in the future without breaking > compatibility. I'm mostly interested in cases when debug info > is not available at all. So perf-probe cache is of no use to me. > > Yes, that syntax do deal with the situation which current 'perf probe' syntax not covered, so not only bpf prologue would benifit from that, maybe we could try to let perf probe involve that. Thanks. -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH] perf tools: Fix build failure on 32-bit arch
Failed in 32bit arch build like this: CC /opt/h00206996/output/perf/arm32/builtin-record.o util/session.c: In function ‘perf_session__warn_about_errors’: util/session.c:1304:9: error: format ‘%lu’ expects argument of type ‘long unsigned int’, but argument 2 has type ‘long long unsigned int’ [-Werror=format=] builtin-report.c: In function ‘perf_evlist__tty_browse_hists’: builtin-report.c:323:2: error: format ‘%lu’ expects argument of type ‘long unsigned int’, but argument 3 has type ‘u64’ [-Werror=format=] Replace %lu format strings in warning message with PRIu64 for u64 'total_lost_samples' to fix this problem. Signed-off-by: He Kuang --- tools/perf/builtin-report.c | 2 +- tools/perf/util/session.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 628090b..32626ea 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -320,7 +320,7 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist, { struct perf_evsel *pos; - fprintf(stdout, "#\n# Total Lost Samples: %lu\n#\n", evlist->stats.total_lost_samples); + fprintf(stdout, "#\n# Total Lost Samples: %" PRIu64 "\n#\n", evlist->stats.total_lost_samples); evlist__for_each(evlist, pos) { struct hists *hists = evsel__hists(pos); const char *evname = perf_evsel__name(pos); diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 88d87bf..f31e024 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -1299,7 +1299,7 @@ static void perf_session__warn_about_errors(const struct perf_session *session) drop_rate = (double)stats->total_lost_samples / (double) (stats->nr_events[PERF_RECORD_SAMPLE] + stats->total_lost_samples); if (drop_rate > 0.05) { - ui__warning("Processed %lu samples and lost %3.2f%% samples!\n\n", + ui__warning("Processed %" PRIu64 " samples and lost %3.2f%% samples!\n\n", stats->nr_events[PERF_RECORD_SAMPLE] + stats->total_lost_samples, drop_rate * 100.0); } -- 1.8.5.2 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH] perf probe: Fix failure to probe events on arm
Fix failure to probe events on arm, problem is introduced by commit 5a51fcd1f30c ("perf probe: Skip kernel symbols which is out of .text"). For some architectures, label '_etext' is not in the .text section(in .notes section for arm/arm64). Label out of .text section is not loaded as symbols and we got a zero value when look up its address, which causes all events be wrongly skiped. This patch uses kernel map->end when failed to get the address of '_etext' and fixes the problem. Problem can be reproduced on arm as following: # perf probe --add='generic_perform_write' generic_perform_write+0 is out of .text, skip it. Probe point 'generic_perform_write' not found. Error: Failed to add events. Reason: No such file or directory (Code: -2) After this patch: # perf probe --add='generic_perform_write' Added new event: probe:generic_perform_write (on generic_perform_write) You can now use it in all perf tools, such as: perf record -e probe:generic_perform_write -aR sleep 1 Signed-off-by: He Kuang --- tools/perf/util/probe-event.c | 16 +++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index daa24a2..ee26961 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -575,8 +575,22 @@ static int post_process_probe_trace_events(struct probe_trace_event *tevs, pr_warning("Relocated base symbol is not found!\n"); return -EINVAL; } - /* Get the address of _etext for checking non-probable text symbol */ + /* Get the address of _etext for checking non-probable text symbol, + for some architectures (e.g. arm, arm64), _etext is out of .text + section and not loaded as symbols, use kernel map->end instead. +*/ etext_addr = kernel_get_symbol_address_by_name("_etext", false); + if (etext_addr == 0) { + struct map *map; + + map = kernel_get_module_map(NULL); + if (!map) { + pr_err("Failed to get a map for kernel\n"); + return -EINVAL; + } + + etext_addr = map->end; + } for (i = 0; i < ntevs; i++) { if (tevs[i].point.address && !tevs[i].point.retprobe) { -- 1.8.5.2 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH] perf probe: Fix failure to probe events on arm
hi, Masami On 2015/6/17 16:52, Masami Hiramatsu wrote: On 2015/06/17 0:26, hekuang wrote: hi, Arnaldo On 06/15/2015 10:49 PM, Arnaldo Carvalho de Melo wrote: Em Mon, Jun 15, 2015 at 08:06:53AM +, He Kuang escreveu: Fix failure to probe events on arm, problem is introduced by commit 5a51fcd1f30c ("perf probe: Skip kernel symbols which is out of .text"). For some architectures, label '_etext' is not in the .text section(in .notes section for arm/arm64). Label out of .text section is not loaded as symbols and we got a zero value when look up its address, which causes all events be wrongly skiped. This patch uses kernel map->end when failed to get the address of '_etext' and fixes the problem. Masami, can't we always use map->end then? Can you please take a look at this patch and ack/nack it? - Arnaldo I think _etext is more accurate than kernel map->end, because __map_groups__fixup_end() is called at the end of dso__load_sym(), which fixes map->end to next_map->start. Comparative result as this: etext_addr=819a1b85, map->end=81ff1000. So if possible, we should use _etext. Hmm, this seems to have another problem. If etext_addr != map->end, we can't relay on that. Is there any good way to get the ".text" address range from symbol map? Until we find it, I'd rather like to skip checking text address range on arm, because it looks meaningless :( OK. Maybe I thought using kernel map->end(always > _etext) is a way to skip checking .text range on arm .. Thank you, Thanks. Problem can be reproduced on arm as following: # perf probe --add='generic_perform_write' generic_perform_write+0 is out of .text, skip it. Probe point 'generic_perform_write' not found. Error: Failed to add events. Reason: No such file or directory (Code: -2) After this patch: # perf probe --add='generic_perform_write' Added new event: probe:generic_perform_write (on generic_perform_write) You can now use it in all perf tools, such as: perf record -e probe:generic_perform_write -aR sleep 1 Signed-off-by: He Kuang --- tools/perf/util/probe-event.c | 16 +++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index daa24a2..ee26961 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -575,8 +575,22 @@ static int post_process_probe_trace_events(struct probe_trace_event *tevs, pr_warning("Relocated base symbol is not found!\n"); return -EINVAL; } - /* Get the address of _etext for checking non-probable text symbol */ + /* Get the address of _etext for checking non-probable text symbol, + for some architectures (e.g. arm, arm64), _etext is out of .text + section and not loaded as symbols, use kernel map->end instead. +*/ etext_addr = kernel_get_symbol_address_by_name("_etext", false); + if (etext_addr == 0) { + struct map *map; + + map = kernel_get_module_map(NULL); + if (!map) { + pr_err("Failed to get a map for kernel\n"); + return -EINVAL; + } + + etext_addr = map->end; + } for (i = 0; i < ntevs; i++) { if (tevs[i].point.address && !tevs[i].point.retprobe) { -- 1.8.5.2 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/ -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/ -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH v2] perf probe: Fix failure to probe events on arm
Fix failure to probe events on arm, problem is introduced by commit 5a51fcd1f30c ("perf probe: Skip kernel symbols which is out of .text"). For some architectures, label '_etext' is not in the .text section(in .notes section for arm/arm64). Label out of .text section is not loaded as symbols and we got a zero value when look up its address, which causes all events be wrongly skiped. This patch skip checking text address range when failed to get the address of '_etext' and fixes the problem. Problem can be reproduced on arm as following: # perf probe --add='generic_perform_write' generic_perform_write+0 is out of .text, skip it. Probe point 'generic_perform_write' not found. Error: Failed to add events. After this patch: # perf probe --add='generic_perform_write' Added new event: probe:generic_perform_write (on generic_perform_write) You can now use it in all perf tools, such as: perf record -e probe:generic_perform_write -aR sleep 1 Signed-off-by: He Kuang --- tools/perf/util/probe-event.c | 6 +- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 076527b..381f23a 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -249,8 +249,12 @@ static void clear_probe_trace_events(struct probe_trace_event *tevs, int ntevs) static bool kprobe_blacklist__listed(unsigned long address); static bool kprobe_warn_out_range(const char *symbol, unsigned long address) { + u64 etext_addr; + /* Get the address of _etext for checking non-probable text symbol */ - if (kernel_get_symbol_address_by_name("_etext", false) < address) + etext_addr = kernel_get_symbol_address_by_name("_etext", false); + + if (etext_addr != 0 && etext_addr < address) pr_warning("%s is out of .text, skip it.\n", symbol); else if (kprobe_blacklist__listed(address)) pr_warning("%s is blacklisted function, skip it.\n", symbol); -- 1.8.5.2 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH RESEND 1/2] tools lib traceevent: Export dynamic symbols used by traceevent plugins
hi, Arnaldo ping.. On 2015/5/28 21:28, He Kuang wrote: Traceevent plugins need dynamic symbols exported from libtraceevent.a, otherwise a dlopen error will occur during plugins loading. This patch uses dynamic-list-file to export dynamic symbols which will be used in plugins to perf executable. The problem is covered up if feature-libpython is enabled, because PYTHON_EMBED_LDOPTS contains '-Xlinker --export-dynamic' which adds all symbols to the dynamic symbol table. So we should reproduce the problem by setting NO_LIBPYTHON=1. Before this patch: (Prepare plugins) $ ls /root/.traceevent/plugins/ plugin_sched_switch.so plugin_function.so ... $ perf record -e 'ftrace:function' ls $ perf script Warning: could not load plugin '/mnt/data/root/.traceevent/plugins/plugin_sched_switch.so' /root/.traceevent/plugins/plugin_sched_switch.so: undefined symbol: pevent_unregister_event_handler Warning: could not load plugin '/root/.traceevent/plugins/plugin_function.so' /root/.traceevent/plugins/plugin_function.so: undefined symbol: warning ... :1049 1049 [000] 9666.754487: ftrace:function: 8118bc50 <-- 8118c5b3 :1049 1049 [000] 9666.754487: ftrace:function: 818e2440 <-- 8118bc75 :1049 1049 [000] 9666.754487: ftrace:function: 8106eee0 <-- 811212e2 After this patch: $ perf record -e 'ftrace:function' ls $ perf script :1049 1049 [000] 9666.754487: ftrace:function: __set_task_comm :1049 1049 [000] 9666.754487: ftrace:function:_raw_spin_lock :1049 1049 [000] 9666.754487: ftrace:function: task_tgid_nr_ns ... Signed-off-by: He Kuang Acked-by: Jiri Olsa --- tools/lib/traceevent/Makefile | 14 +- tools/perf/Makefile.perf | 14 -- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/tools/lib/traceevent/Makefile b/tools/lib/traceevent/Makefile index 8464039..6daaff6 100644 --- a/tools/lib/traceevent/Makefile +++ b/tools/lib/traceevent/Makefile @@ -23,6 +23,7 @@ endef # Allow setting CC and AR, or setting CROSS_COMPILE as a prefix. $(call allow-override,CC,$(CROSS_COMPILE)gcc) $(call allow-override,AR,$(CROSS_COMPILE)ar) +$(call allow-override,NM,$(CROSS_COMPILE)nm) EXT = -std=gnu99 INSTALL = install @@ -157,8 +158,9 @@ PLUGINS_IN := $(PLUGINS:.so=-in.o) TE_IN:= $(OUTPUT)libtraceevent-in.o LIB_FILE := $(addprefix $(OUTPUT),$(LIB_FILE)) +DYNAMIC_LIST_FILE := $(OUTPUT)libtraceevent-dynamic-list -CMD_TARGETS = $(LIB_FILE) $(PLUGINS) +CMD_TARGETS = $(LIB_FILE) $(PLUGINS) $(DYNAMIC_LIST_FILE) TARGETS = $(CMD_TARGETS) @@ -175,6 +177,9 @@ $(OUTPUT)libtraceevent.so: $(TE_IN) $(OUTPUT)libtraceevent.a: $(TE_IN) $(QUIET_LINK)$(RM) $@; $(AR) rcs $@ $^ +$(OUTPUT)libtraceevent-dynamic-list: $(PLUGINS) + $(QUIET_GEN)$(call do_generate_dynamic_list_file, $(PLUGINS), $@) + plugins: $(PLUGINS) __plugin_obj = $(notdir $@) @@ -244,6 +249,13 @@ define do_install_plugins done endef +define do_generate_dynamic_list_file + (echo '{'; \ + $(NM) -u -D $1 | awk 'NF>1 {print "\t"$$2";"}' | sort -u;\ + echo '};'; \ + ) > $2 +endef + install_lib: all_cmd install_plugins $(call QUIET_INSTALL, $(LIB_FILE)) \ $(call do_install,$(LIB_FILE),$(libdir_SQ)) diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 5816a3b..b1dfcd8 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -173,6 +173,9 @@ endif LIBTRACEEVENT = $(TE_PATH)libtraceevent.a export LIBTRACEEVENT +LIBTRACEEVENT_DYNAMIC_LIST = $(TE_PATH)libtraceevent-dynamic-list +LDFLAGS += -Xlinker --dynamic-list=$(LIBTRACEEVENT_DYNAMIC_LIST) + LIBAPI = $(LIB_PATH)libapi.a export LIBAPI @@ -278,7 +281,7 @@ build := -f $(srctree)/tools/build/Makefile.build dir=. obj $(PERF_IN): $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h FORCE $(Q)$(MAKE) $(build)=perf -$(OUTPUT)perf: $(PERFLIBS) $(PERF_IN) +$(OUTPUT)perf: $(PERFLIBS) $(PERF_IN) $(LIBTRACEEVENT_DYNAMIC_LIST) $(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $(PERF_IN) $(LIBS) -o $@ $(GTK_IN): FORCE @@ -373,7 +376,13 @@ $(LIB_FILE): $(LIBPERF_IN) LIBTRACEEVENT_FLAGS += plugin_dir=$(plugindir_SQ) $(LIBTRACEEVENT): FORCE - $(Q)$(MAKE) -C $(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) O=$(OUTPUT) $(OUTPUT)libtraceevent.a plugins + $(Q)$(MAKE) -C $(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) O=$(OUTPUT) $(OUTPUT)libtraceevent.a + +libtraceevent_plugins: FORCE + $(Q)$(MAKE) -C $(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) O=$(OUTPUT) plugins + +$(LIBTRACEEVENT_DYNAMIC_LIST): libtraceevent_plugin
Re: [PATCH] perf record: Fix perf.data size in no-buildid mode
ping.. On 2015/5/28 21:17, He Kuang wrote: The size of perf.data is missing update in no-buildid mode, which gives wrong output result. Before this patch: $ perf.perf record -B -e syscalls:sys_enter_open uname Linux [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.000 MB perf.data ] After this patch: $ perf.perf record -B -e syscalls:sys_enter_open uname Linux [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.001 MB perf.data ] Signed-off-by: He Kuang --- tools/perf/builtin-record.c | 6 ++ 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 91aa2a3..d3731cc 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -345,12 +345,9 @@ static int process_buildids(struct record *rec) struct perf_data_file *file = &rec->file; struct perf_session *session = rec->session; - u64 size = lseek(perf_data_file__fd(file), 0, SEEK_CUR); - if (size == 0) + if (file->size == 0) return 0; - file->size = size; - /* * During this process, it'll load kernel map and replace the * dso->long_name to a real pathname it found. In this case @@ -719,6 +716,7 @@ out_child: if (!err && !file->is_pipe) { rec->session->header.data_size += rec->bytes_written; + file->size = lseek(perf_data_file__fd(file), 0, SEEK_CUR); if (!rec->no_buildid) { process_buildids(rec); -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [RFC PATCH v4 3/3] bpf: Introduce function for outputing data to perf event
Hi, Alexi Thank you for your guidence, and by referencing your last mail and other llvm backends, I found setting BPFMCAsmInfo::SupportsDebugInformation = true in BPFMCAsmInfo.h and fix some unhandeled switch can make llc output debug_info, but important information is missing in the result: bpf: <1><2a>: Abbrev Number: 2 (DW_TAG_subprogram) <2b> DW_AT_low_pc : 0x0 <33> DW_AT_high_pc : 0x60 <37> Unknown AT value: 3fe7: 1 <37> DW_AT_frame_base : 1 byte block: 5a (DW_OP_reg10 (r10)) <39> DW_AT_name: (indirect string, offset: 0x0): clang version 3.7.0 (http://llvm.org/git/clang.git.. <3d> DW_AT_decl_file : 1 <3e> DW_AT_decl_line : 3 <3f> DW_AT_prototyped : 1 <3f> DW_AT_type: <0x65> <43> DW_AT_external: 1 <43> Unknown AT value: 3fe1: 1 <2><43>: Abbrev Number: 3 (DW_TAG_formal_parameter) <44> DW_AT_name: (indirect string, offset: 0x0): clang version 3.7.0 (http://llvm.org/git/clang.git.. <48> DW_AT_decl_file : 1 <49> DW_AT_decl_line : 3 <4a> DW_AT_type: <0x65> Compares to x86 platform result: <1><26>: Abbrev Number: 2 (DW_TAG_subprogram) <27> DW_AT_low_pc : 0x0 <2b> DW_AT_high_pc : 0x16 <2f> Unknown AT value: 3fe7: 1 <2f> DW_AT_frame_base : 1 byte block: 54 (DW_OP_reg4 (esp)) <31> DW_AT_name: (indirect string, offset: 0xcf): testprog <35> DW_AT_decl_file : 1 <36> DW_AT_decl_line : 3 <37> DW_AT_prototyped : 1 <37> DW_AT_type: <0x65> <3b> DW_AT_external: 1 <3b> Unknown AT value: 3fe1: 1 <2><3b>: Abbrev Number: 3 (DW_TAG_formal_parameter) <3c> DW_AT_location: 2 byte block: 91 4 (DW_OP_fbreg: 4) <3f> DW_AT_name: (indirect string, offset: 0xdc): myvar_a <43> DW_AT_decl_file : 1 <44> DW_AT_decl_line : 3 <45> DW_AT_type: <0x65> The bpf result lacks of DW_AT_location, and DW_AT_name gives no infomation. Then I used 'llc print-after*' command to check each pass and wanted to find by which step the debug infomation is dropped, things looks similar until the passes between 'verify' and 'expand-isel-pseudos': x86: $ llc -march=x86 --print-before-all -print-after-all -stop-after=expand-isel-pseudos test.ll # *** IR Dump Before Expand ISel Pseudo-instructions ***: # Machine code for function testprog: SSA Frame Objects: fi#-2: size=4, align=4, fixed, at location [SP+8] fi#-1: size=4, align=16, fixed, at location [SP+4] BB#0: derived from LLVM BB %entry DBG_VALUE , 0, !"myvar_a", ; line no:3 ^^ DBG_VALUE , 0, !"myvar_b", ; line no:3 %vreg0 = MOV32rm , 1, %noreg, 0, %noreg; mem:LD4[FixedStack-2] ; GR32:%vreg0 bpf: $ llc -march=bpf --print-before-all -print-after-all -stop-after=expand-isel-pseudos test.ll # *** IR Dump Before Expand ISel Pseudo-instructions ***: # Machine code for function testprog: SSA Function Live Ins: %R1 in %vreg0, %R2 in %vreg1 BB#0: derived from LLVM BB %entry Live Ins: %R1 %R2 %vreg1 = COPY %R2; GPR:%vreg1 %vreg0 = COPY %R1; GPR:%vreg0 %vreg2 = LD_imm64 2147483648; GPR:%vreg2 I think maybe this missing 'DBG_VALUE' causes the problem, but I'm stuck here and hope you can give more advice. Thank you! On 2015/7/17 12:27, Alexei Starovoitov wrote: clang -O2 -emit-llvm -g a.c -S -o a.ll -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: llvm bpf debug info. Re: [RFC PATCH v4 3/3] bpf: Introduce function for outputing data to perf event
Hi, Alexei On 2015/7/24 11:20, Alexei Starovoitov wrote: On 7/23/15 1:49 PM, Alexei Starovoitov wrote: On 7/23/15 4:54 AM, He Kuang wrote: trimmed cc-list, since it's not related to kernel. Thank you for your guidence, and by referencing your last mail and other llvm backends, I found setting BPFMCAsmInfo::SupportsDebugInformation = true in BPFMCAsmInfo.h thanks! yes. it was missing. and fix some unhandeled switch can make llc output debug_info, what do you mean ? but important information is missing in the result: hmm. I see slightly different picture. With 'clang -O2 -target bpf -g -S a.c' I see all the right info inside .s file. with '-c a.c' for some reasons it produces bogus offset: Abbrev Offset: 0x Pointer Size: 8 /usr/local/bin/objdump: Warning: Debug info is corrupted, abbrev offset () is larger than abbrev section size (4b) and objdump fails to parse .o I'm using llvm trunk 3.8. Do you see this as well? there were few issues related to relocations. Fixed it up and pushed to llvm trunk r243087. Please pull and give it a try. AT_location should be correct, but AT_name still looks buggy. I've pulled the lastest version "[bpf] initial support for debug_info" and tested it. This version can output debug_info but still not generate correct AT_location, I tested as following: $ cat > main.c < test.obj.x86.dump $ objdump --dwarf=info test.obj.bpf > test.obj.bpf.dump Compare those two dump files: test.obj.x86.dump: <2><43>: Abbrev Number: 3 (DW_TAG_formal_parameter) <44> DW_AT_location: 3 byte block: 55 93 4(DW_OP_reg5 (rdi); DW_OP_piece: 4) <48> DW_AT_name: (indirect string, offset: 0xdc): myvar_a <4c> DW_AT_decl_file : 1 <4d> DW_AT_decl_line : 1 <4e> DW_AT_type: <0x71> test.obj.bpf.dump: <2><43>: Abbrev Number: 3 (DW_TAG_formal_parameter) <44> DW_AT_name : (indirect string, offset: 0x0): clang version 3.8.0 (http://llvm.org/git/clang.git 3a7c733b80f156a547f3f1517e6fbce9c0a33026) (http://llvm.org/git/llvm.git 90908cb34d73460d3 a83e2194a58d82c6d1f199) <48> DW_AT_decl_file : 1 <49> DW_AT_decl_line : 1 <4a> DW_AT_type: <0x65> No DW_AT_location info for formal parameters, but if we change the function 'testprog' to 'main', DW_AT_location of formal parameters appear but that of local variables are still missed, don't know why.. $ cat > main.c < int main(int argc, char *argv[]) { int myvar_a, myvar_b; int myvar_c; myvar_c = myvar_a + myvar_b; return myvar_c; } test.obj.bpf.dump: <2><43>: Abbrev Number: 3 (DW_TAG_formal_parameter) <44> DW_AT_location: 1 byte block: 51 (DW_OP_reg1 (r1)) <46> DW_AT_name: (indirect string, offset: 0x0): clang version 3.8. .. <2><5d>: Abbrev Number: 4 (DW_TAG_variable) <5e> DW_AT_name: (indirect string, offset: 0x0): clang version 3.8. test.obj.x86.dump: <2><43>: Abbrev Number: 3 (DW_TAG_formal_parameter) <44> DW_AT_location: 3 byte block: 55 93 4(DW_OP_reg5 (rdi); DW_OP_piece: 4) <48> DW_AT_name: (indirect string, offset: 0xd8): argc .. <2><5f>: Abbrev Number: 4 (DW_TAG_variable) <60> DW_AT_name: (indirect string, offset: 0xe7): myvar_a .. Thank you. -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [LLVMdev] Cc llvmdev: Re: llvm bpf debug info. Re: [RFC PATCH v4 3/3] bpf: Introduce function for outputing data to perf event
Hi, Alexei On 2015/7/30 1:13, Alexei Starovoitov wrote: On 7/29/15 2:38 AM, He Kuang wrote: Hi, Alexei On 2015/7/28 10:18, Alexei Starovoitov wrote: On 7/25/15 3:04 AM, He Kuang wrote: I noticed that for 64-bit elf format, the reloc sections have 'Addend' in the entry, but there's no 'Addend' info in bpf elf file(64bit). I think there must be something wrong in the process of .s -> .o, which related to 64bit/32bit. Anyway, we can parse out the AT_name now, DW_AT_LOCATION still missed and need your help. Another thing about DW_AT_name, we've already found that the name string is stored indirectly and needs relocation which is architecture specific, while the e_machine info in bpf obj file is "unknown", both objdump and libdw cannot parse DW_AT_name correctly. Should we just use a known architeture for bpf object file instead of "unknown"? If so, we can use the existing relocation codes in libdw and get DIE name by simply invoking dwarf_diename(). The drawback of this method is that, e.g. we use "x86-64" instead, is hard to distinguish bpf obj file with x86-64 elf file. Do you think this is ok? Otherwise, for not touching libdw, we should reimplement the relocation codes already in libdw for bpf elf file with "unknown" machine info specially in perf. I wonder whether it is worth doing this and what's your opinion? Thank you. index directly: __bpf_trace_output_data(__builtin_dwarf_type(myvar_a), &myvar_a, size); probably both A and B won't really work when programs get bigger and optimizations will start moving lines around. the builtin_dwarf_type idea is actually quite interesting. Potentially that builtin can stringify type name and later we can search it in dwarf. Please take a look how to add such builtin. There are few similar builtins that deal with exception handling and need type info. May be they can be reused. Like: int_eh_typeid_for and int_eh_dwarf_cfa -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: llvm bpf debug info. Re: [RFC PATCH v4 3/3] bpf: Introduce function for outputing data to perf event
Hi, Alexei On 2015/7/28 10:18, Alexei Starovoitov wrote: On 7/25/15 3:04 AM, He Kuang wrote: I noticed that for 64-bit elf format, the reloc sections have 'Addend' in the entry, but there's no 'Addend' info in bpf elf file(64bit). I think there must be something wrong in the process of .s -> .o, which related to 64bit/32bit. Anyway, we can parse out the AT_name now, DW_AT_LOCATION still missed and need your help. looks like objdump/llvm-dwarfdump can only read known EM, but that that shouldn't be the problem for your dwarf reader right? It should be able to recognize id-s of ELF::R_X86_64_* relo used right? As far as AT_location for testprog.c it seems there is no info for local variables because they were optimized away. With -O0 I see AT_location being emitted. Also line number info seems to be good in both cases. But in our case, we don't need this anyway, no? we need to see the types of structs mainly or you have some other use cases? I think line number info would be great to correlate the error reported by verifier into specific line in C. Yes, without AT_location, we can lookup the user output data type by line number, but there're some issues when we look deep. There're two steps of work that should be done in user space, first we embed data type into bpf output record, then we use this type, or index or some other identifier to lookup the type from dwarf info, so we got a few plans. * Plan A. Use line number to identify the user data type Predefined macros: #define DEFINE_BPF_OUTPUT_DATA(type, var) \ const int BPF_OUTPUT_LINE__##var = __LINE__; type var; #define BPF_OUTPUT_TRACE_DATA(data, size) \ __bpf_output_trace_data(BPF_OUTPUT_LINE__##data, &data, size) User defined BPF code: struct user_define_struct { ... }; int testprog(int myvar_a, long myvar_b) { DEFINE_BPF_OUTPUT_DATA(struct user_define_struct, myvar_c); BPF_OUTPUT_TRACE_DATA(myvar_c, sizeof(myvar_c)); ... We use macros to embed linenum implicitly, which leads an extra restriction that user should not define multiple variables in the same line and not split the macro over multiple lines, like this: 22 DEFINE_BPF_OUTPUT_DATA(struct xxtype, a); DEFINE_BPF_OUTPUT_DATA(struct xxtype, b); Or 22 DEFINE_BPF_OUTPUT_DATA(struct user_define_struct, 23 myvar_c); DW_AT_decl_line = 22, while __LINE__ = 23 So we should add verifier in the llvm BPF backend to warn on the above codes. * Plan B. Lookup variable type from dwarf AT_location info We can make use of the output data variable's address, for bpf is a minus offset to frame base. Then lookup matched offset from location info(e.g. "DW_OP_fbreg: -32") to identify the variable type. For getting the frame base address, we can use builtin functions like __builtin_frame_base() and __builtin_dwarf_cfa() which returns the call frame base address. Currently those builtin functions are not implemented in BPF lower operation yet, so we tested our bpf program by using a variable tag on frame base, as following: struct user_define_struct { ... }; typedef struct {} frame_base_tag; int testprog(void) { frame_base_tag BPF_FRAME_BASE; struct user_define_struct myvar_a; __bpf_trace_output_data((void *)&myvar_a - (void *)&BPF_FRAME_BASE, &myvar_a, sizeof(myvar_a)); ... The first argument of __bpf_trace_output_data() will be caculated and it's easy to traverse the variable DIEs in dwarf info and check each DW_AT_location attribute to find the corresponding variable type. The things let us worry about is the opimization may reuse the stack space which can cause different variables share the same address, by some rough tests that kind of optimization does not appear. * Comparison Plan A needs less effort and easy to implement, but requires more check to ensure user not use multiple definition in the same line and not use macro cross lines. The advantages of plan B is that we do not need introduce macros showed in above example and all the things are done implicitly, but the AT_location info is the prerequisite of this plan, I'm not sure whether we can guarantee this info in dwarf or not. Another way we can think of is adding new builtin functions to indicate the compilier to generate codes return the dwarf type index directly: __bpf_trace_output_data(__builtin_dwarf_type(myvar_a), &myvar_a, size); What's your opinion on those plans, and do you have more suggestion? Thank you. -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: llvm bpf debug info. Re: [RFC PATCH v4 3/3] bpf: Introduce function for outputing data to perf event
Hi, Alexei On 2015/7/24 12:16, He Kuang wrote: Hi, Alexei On 2015/7/24 11:20, Alexei Starovoitov wrote: On 7/23/15 1:49 PM, Alexei Starovoitov wrote: On 7/23/15 4:54 AM, He Kuang wrote: trimmed cc-list, since it's not related to kernel. Thank you for your guidence, and by referencing your last mail and other llvm backends, I found setting BPFMCAsmInfo::SupportsDebugInformation = true in BPFMCAsmInfo.h thanks! yes. it was missing. and fix some unhandeled switch can make llc output debug_info, what do you mean ? but important information is missing in the result: hmm. I see slightly different picture. With 'clang -O2 -target bpf -g -S a.c' I see all the right info inside .s file. with '-c a.c' for some reasons it produces bogus offset: Abbrev Offset: 0x Pointer Size: 8 /usr/local/bin/objdump: Warning: Debug info is corrupted, abbrev offset () is larger than abbrev section size (4b) and objdump fails to parse .o I'm using llvm trunk 3.8. Do you see this as well? there were few issues related to relocations. Fixed it up and pushed to llvm trunk r243087. Please pull and give it a try. AT_location should be correct, but AT_name still looks buggy. I've pulled the lastest version "[bpf] initial support for debug_info" and tested it. This version can output debug_info but still not generate correct AT_location, I tested as following: $ cat > main.c < test.obj.x86.dump $ objdump --dwarf=info test.obj.bpf > test.obj.bpf.dump Compare those two dump files: test.obj.x86.dump: <2><43>: Abbrev Number: 3 (DW_TAG_formal_parameter) <44> DW_AT_location: 3 byte block: 55 93 4(DW_OP_reg5 (rdi); DW_OP_piece: 4) <48> DW_AT_name: (indirect string, offset: 0xdc): myvar_a <4c> DW_AT_decl_file : 1 <4d> DW_AT_decl_line : 1 <4e> DW_AT_type: <0x71> test.obj.bpf.dump: <2><43>: Abbrev Number: 3 (DW_TAG_formal_parameter) <44> DW_AT_name : (indirect string, offset: 0x0): clang version 3.8.0 (http://llvm.org/git/clang.git 3a7c733b80f156a547f3f1517e6fbce9c0a33026) (http://llvm.org/git/llvm.git 90908cb34d73460d3 a83e2194a58d82c6d1f199) <48> DW_AT_decl_file : 1 <49> DW_AT_decl_line : 1 <4a> DW_AT_type: <0x65> No DW_AT_location info for formal parameters, but if we change the function 'testprog' to 'main', DW_AT_location of formal parameters appear but that of local variables are still missed, don't know why.. $ cat > main.c < int main(int argc, char *argv[]) { int myvar_a, myvar_b; int myvar_c; myvar_c = myvar_a + myvar_b; return myvar_c; } test.obj.bpf.dump: <2><43>: Abbrev Number: 3 (DW_TAG_formal_parameter) <44> DW_AT_location: 1 byte block: 51 (DW_OP_reg1 (r1)) <46> DW_AT_name: (indirect string, offset: 0x0): clang version 3.8. .. <2><5d>: Abbrev Number: 4 (DW_TAG_variable) <5e> DW_AT_name: (indirect string, offset: 0x0): clang version 3.8. test.obj.x86.dump: <2><43>: Abbrev Number: 3 (DW_TAG_formal_parameter) <44> DW_AT_location: 3 byte block: 55 93 4(DW_OP_reg5 (rdi); DW_OP_piece: 4) <48> DW_AT_name: (indirect string, offset: 0xd8): argc .. <2><5f>: Abbrev Number: 4 (DW_TAG_variable) <60> DW_AT_name: (indirect string, offset: 0xe7): myvar_a .. Thank you. Share some infomation on debuging bpf debuginfo problem. An error "error: failed to compute relocation: Unknown" can be found if we use llvm-dwarfdump tools to dump the object file, debuging on that error, it seems there's no support for type 'BPF' in llvm/include/llvm/Support/MachO.h, and llvm-dwarfdump fails to find the corresponding VisitElf method. Then I have a rough test which forces RelocVisitor to use 'visitELF_386_32', and got the correct DW_AT_name in the output: 0x0043: DW_TAG_formal_parameter [3] DW_AT_name [DW_FORM_strp] ( .debug_str[0x00dc] = "myvar_a") DW_AT_decl_file [DW_FORM_data1] ("testllvm/main.c") DW_AT_decl_line [DW_FORM_data1] (3) DW_AT_type [DW_FORM_ref4] (cu + 0x0065 => {0x0065}) I noticed that for 64-bit elf format, the reloc sections have 'Addend' in the entry, but there's no 'Addend' info in bpf elf file(64bit). I think there must be something wrong in the process of .s -> .o, which related to 64bit/32bit
[PATCH] module: Fix missing to hold module_mutex lock in module_kallsyms_lookup_name
Function find_module_all() searches for module by name and must be called with module_mutex. module_kallsyms_lookup_name() calls it without this mutex which emits a warning message (CONFIG_LOCKDEP=y) by failed assertion for testing this module_mutex lock, as following: [ 202.877152] [ cut here ] [ 202.881070] WARNING: CPU: 0 PID: 1010 at kernel/module.c:281 module_assert_mutex+0x35/0x40() [ 202.885446] Modules linked in: test_bpf [ 202.886997] CPU: 0 PID: 1010 Comm: perf Tainted: G W 4.2.0-rc3+ #5 ... This patch wraps this call with mutex_{lock,unlock} and fix the bug. Signed-off-by: He Kuang --- kernel/module.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kernel/module.c b/kernel/module.c index 4d2b82e..43d728b 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -3802,8 +3802,10 @@ unsigned long module_kallsyms_lookup_name(const char *name) /* Don't lock: we're in enough trouble already. */ preempt_disable(); if ((colon = strchr(name, ':')) != NULL) { + mutex_lock(&module_mutex); if ((mod = find_module_all(name, colon - name, false)) != NULL) ret = mod_find_symname(mod, colon+1); + mutex_unlock(&module_mutex); } else { list_for_each_entry_rcu(mod, &modules, list) { if (mod->state == MODULE_STATE_UNFORMED) -- 1.8.5.2 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [RFC PATCH v5 0/3] Make eBPF programs output data to perf
On 2015/7/14 21:35, Steven Rostedt wrote: On Mon, 13 Jul 2015 20:10:29 -0700 Alexei Starovoitov wrote: On 7/13/15 6:59 PM, He Kuang wrote: This version we output bpf trace events in a hex array, the results for three u64 integers in previous sample changed to this: dd 1042 [000] 1296.122951: bpf:bpf_output_data: 7a ca aa c6 2d 01 00 00 95 87 ec ca 2d 01 00 00 1b bd 41 04 00 00 00 00 typo in the above. It's not 3 u64 integers, but variable number of u8. Whole thing looks good. I've acked patch 3. Hopefully Steven can review patches 1 and 2. I'll try to get around to it ;-) -- Steve Awaiting your reply ;-) Thank you. -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 4/8] perf build: Add build-test for debug-frame on arm/arm64
Debug-frame for remote platforms is not related to the host platform, so we should test each platform separately. Signed-off-by: He Kuang --- tools/build/Makefile.feature | 3 ++- tools/build/feature/Makefile | 10 +++--- tools/build/feature/test-libunwind-debug-frame-aarch64.c | 16 tools/build/feature/test-libunwind-debug-frame-arm.c | 16 tools/build/feature/test-libunwind-debug-frame.c | 16 5 files changed, 41 insertions(+), 20 deletions(-) create mode 100644 tools/build/feature/test-libunwind-debug-frame-aarch64.c create mode 100644 tools/build/feature/test-libunwind-debug-frame-arm.c delete mode 100644 tools/build/feature/test-libunwind-debug-frame.c diff --git a/tools/build/Makefile.feature b/tools/build/Makefile.feature index 139e99c..87dd96b9 100644 --- a/tools/build/Makefile.feature +++ b/tools/build/Makefile.feature @@ -73,7 +73,8 @@ FEATURE_TESTS_EXTRA :=\ libbabeltrace \ liberty \ liberty-z \ - libunwind-debug-frame + libunwind-debug-frame-arm \ + libunwind-debug-frame-aarch64 FEATURE_TESTS ?= $(FEATURE_TESTS_BASIC) diff --git a/tools/build/feature/Makefile b/tools/build/feature/Makefile index f4fe3bc..38a9896 100644 --- a/tools/build/feature/Makefile +++ b/tools/build/feature/Makefile @@ -26,11 +26,12 @@ FILES= \ test-libslang.bin \ test-libcrypto.bin \ test-libunwind.bin \ - test-libunwind-debug-frame.bin \ test-libunwind-x86.bin \ test-libunwind-x86_64.bin \ test-libunwind-arm.bin \ test-libunwind-aarch64.bin \ + test-libunwind-debug-frame-arm.bin \ + test-libunwind-debug-frame-aarch64.bin \ test-pthread-attr-setaffinity-np.bin\ test-stackprotector-all.bin \ test-timerfd.bin\ @@ -105,8 +106,6 @@ $(OUTPUT)test-numa_num_possible_cpus.bin: $(OUTPUT)test-libunwind.bin: $(BUILD) -lelf -$(OUTPUT)test-libunwind-debug-frame.bin: - $(BUILD) -lelf $(OUTPUT)test-libunwind-x86.bin: $(BUILD) -lelf -lunwind-x86 @@ -119,6 +118,11 @@ $(OUTPUT)test-libunwind-arm.bin: $(OUTPUT)test-libunwind-aarch64.bin: $(BUILD) -lelf -lunwind-aarch64 +$(OUTPUT)test-libunwind-debug-frame-arm.bin: + $(BUILD) -lelf -lunwind-arm + +$(OUTPUT)test-libunwind-debug-frame-aarch64.bin: + $(BUILD) -lelf -lunwind-aarch64 $(OUTPUT)test-libaudit.bin: $(BUILD) -laudit diff --git a/tools/build/feature/test-libunwind-debug-frame-aarch64.c b/tools/build/feature/test-libunwind-debug-frame-aarch64.c new file mode 100644 index 000..2284467 --- /dev/null +++ b/tools/build/feature/test-libunwind-debug-frame-aarch64.c @@ -0,0 +1,16 @@ +#include +#include + +extern int +UNW_OBJ(dwarf_find_debug_frame) (int found, unw_dyn_info_t *di_debug, +unw_word_t ip, unw_word_t segbase, +const char *obj_name, unw_word_t start, +unw_word_t end); + +#define dwarf_find_debug_frame UNW_OBJ(dwarf_find_debug_frame) + +int main(void) +{ + dwarf_find_debug_frame(0, NULL, 0, 0, NULL, 0, 0); + return 0; +} diff --git a/tools/build/feature/test-libunwind-debug-frame-arm.c b/tools/build/feature/test-libunwind-debug-frame-arm.c new file mode 100644 index 000..f988596 --- /dev/null +++ b/tools/build/feature/test-libunwind-debug-frame-arm.c @@ -0,0 +1,16 @@ +#include +#include + +extern int +UNW_OBJ(dwarf_find_debug_frame) (int found, unw_dyn_info_t *di_debug, +unw_word_t ip, unw_word_t segbase, +const char *obj_name, unw_word_t start, +unw_word_t end); + +#define dwarf_find_debug_frame UNW_OBJ(dwarf_find_debug_frame) + +int main(void) +{ + dwarf_find_debug_frame(0, NULL, 0, 0, NULL, 0, 0); + return 0; +} diff --git a/tools/build/feature/test-libunwind-debug-frame.c b/tools/build/feature/test-libunwind-debug-frame.c deleted file mode 100644 index 0ef8087..000 --- a/tools/build/feature/test-libunwind-debug-frame.c +++ /dev/null @@ -1,16 +0,0 @@ -#include -#include - -extern int -UNW_OBJ(dwarf_find_debug_frame) (int found, unw_dyn_info_t *di_debug, -unw_word_t ip, unw_word_t segbase, -const char *obj_name, unw_word_t start, -unw_word_t end); - -#define dwarf_find_debug_frame UNW_OBJ(dwarf_find_debug_frame) - -int main(void) -{ - dwarf_find_debug_frame(0, NULL, 0, 0, NULL, 0, 0); - return 0; -} -- 1.8.5.2
[PATCH 0/8] Add support for remote unwind
Currently, perf script uses host unwind methods to parse perf.data callchain info regardless of the target architecture. So we get wrong result and no promotion when do remote unwind on other platforms/machines. This patch set adds build tests for the supported platforms for remote unwinding, and checks the map elf info for each thread, use remote unwind methods instead. Only x86 and aarch64 is added in this patch set to show the work flow, other platforms can be added easily. We can see the right result for unwind infos on different machines, for example: we record perf.data on i686 qemu with '-g' option and parse it on x86_64 machine. before this patchset: hello 1071 [000] 417.567832: probe:sys_close: (c1169d60) c1169d61 sys_close ([kernel.kallsyms]) c189c0d7 sysenter_past_esp ([kernel.kallsyms]) b77c8ba9 [unknown] ([vdso32]) after: hello 1071 [000] 417.567832: probe:sys_close: (c1169d60) c1169d61 sys_close ([kernel.kallsyms]) c189c0d7 sysenter_past_esp ([kernel.kallsyms]) b77c8ba9 [unknown] ([vdso32]) b76e51cc close (/lib/libc-2.22.so) 804842e fib (/tmp/hello) 804849d main (/tmp/hello) b762546e __libc_start_main (/lib/libc-2.22.so) 8048341 _start (/tmp/hello) Thanks, discussion welcomed. He Kuang (8): perf tools: Omit DWARF judgement when recording dwarf callchain perf script: Add options for custom vdso name perf build: Add build-test for libunwind cross-platforms support perf build: Add build-test for debug-frame on arm/arm64 perf tools: Promote proper messages for cross-platform unwind perf callchain: Add support for cross-platform unwind perf callchain: Support x86 target platform perf callchain: Support aarch64 cross-platform tools/build/Makefile.feature | 11 +++- tools/build/feature/Makefile | 26 +++- tools/build/feature/test-libunwind-aarch64.c | 26 tools/build/feature/test-libunwind-arm.c | 27 + .../feature/test-libunwind-debug-frame-aarch64.c | 16 + .../build/feature/test-libunwind-debug-frame-arm.c | 16 + tools/build/feature/test-libunwind-debug-frame.c | 16 - tools/build/feature/test-libunwind-x86.c | 27 + tools/build/feature/test-libunwind-x86_64.c| 27 + .../arch/arm64/include/libunwind/libunwind-arch.h | 18 ++ tools/perf/arch/arm64/util/unwind-libunwind.c | 5 +- .../arch/x86/include/libunwind/libunwind-arch.h| 18 ++ tools/perf/arch/x86/util/unwind-libunwind.c| 42 + tools/perf/builtin-script.c| 2 + tools/perf/config/Makefile | 35 ++- tools/perf/util/Build | 13 +++- tools/perf/util/dso.c | 7 +++ tools/perf/util/dso.h | 1 + tools/perf/util/symbol-elf.c | 16 + tools/perf/util/symbol.c | 50 tools/perf/util/symbol.h | 3 + tools/perf/util/thread.c | 70 -- tools/perf/util/thread.h | 14 - tools/perf/util/unwind-libunwind.c | 50 +--- tools/perf/util/unwind-libunwind_common.c | 60 +++ tools/perf/util/unwind.h | 30 ++ tools/perf/util/util.c | 2 - 27 files changed, 589 insertions(+), 39 deletions(-) create mode 100644 tools/build/feature/test-libunwind-aarch64.c create mode 100644 tools/build/feature/test-libunwind-arm.c create mode 100644 tools/build/feature/test-libunwind-debug-frame-aarch64.c create mode 100644 tools/build/feature/test-libunwind-debug-frame-arm.c delete mode 100644 tools/build/feature/test-libunwind-debug-frame.c create mode 100644 tools/build/feature/test-libunwind-x86.c create mode 100644 tools/build/feature/test-libunwind-x86_64.c create mode 100644 tools/perf/arch/arm64/include/libunwind/libunwind-arch.h create mode 100644 tools/perf/arch/x86/include/libunwind/libunwind-arch.h create mode 100644 tools/perf/util/unwind-libunwind_common.c -- 1.8.5.2
[PATCH 6/8] perf callchain: Add support for cross-platform unwind
Use thread specific unwind ops to unwind cross-platform callchains. Before this patch, unwind methods is suitable for local unwind, this patch changes the fixed methods to thread/map related. Each time a map is inserted, we find the target arch and see if this platform can be remote unwind. In this patch, we test for x86 platform and only show proper messages. The real unwind methods are not implemented, will be introduced in next patch. Signed-off-by: He Kuang --- tools/perf/config/Makefile| 19 -- tools/perf/util/Build | 3 +- tools/perf/util/thread.c | 29 +++ tools/perf/util/thread.h | 14 +++- tools/perf/util/unwind-libunwind.c| 48 + tools/perf/util/unwind-libunwind_common.c | 60 +++ tools/perf/util/unwind.h | 22 7 files changed, 178 insertions(+), 17 deletions(-) create mode 100644 tools/perf/util/unwind-libunwind_common.c diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index a86b864..16f14b1 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile @@ -345,14 +345,24 @@ ifeq ($(ARCH),powerpc) endif ifndef NO_LIBUNWIND + have_libunwind = ifeq ($(feature-libunwind-x86), 1) -LIBUNWIND_LIBS += -lunwind-x86 $(call detected,CONFIG_LIBUNWIND_X86) CFLAGS += -DHAVE_LIBUNWIND_X86_SUPPORT +LDFLAGS += -lunwind -lunwind-x86 +have_libunwind = 1 endif ifneq ($(feature-libunwind), 1) msg := $(warning No libunwind found. Please install libunwind-dev[el] >= 1.1 and/or set LIBUNWIND_DIR); +NO_LOCAL_LIBUNWIND := 1 + else +have_libunwind = 1 +CFLAGS += -DHAVE_LIBUNWIND_LOCAL_SUPPORT +$(call detected,CONFIG_LOCAL_LIBUNWIND) + endif + + ifneq ($(have_libunwind), 1) NO_LIBUNWIND := 1 endif endif @@ -392,7 +402,7 @@ else NO_DWARF_UNWIND := 1 endif -ifndef NO_LIBUNWIND +ifndef NO_LOCAL_LIBUNWIND ifeq ($(ARCH),$(filter $(ARCH),arm arm64)) $(call feature_check,libunwind-debug-frame) ifneq ($(feature-libunwind-debug-frame), 1) @@ -403,12 +413,15 @@ ifndef NO_LIBUNWIND # non-ARM has no dwarf_find_debug_frame() function: CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME endif - CFLAGS += -DHAVE_LIBUNWIND_SUPPORT EXTLIBS += $(LIBUNWIND_LIBS) CFLAGS += $(LIBUNWIND_CFLAGS) LDFLAGS += $(LIBUNWIND_LDFLAGS) endif +ifndef NO_LIBUNWIND + CFLAGS += -DHAVE_LIBUNWIND_SUPPORT +endif + ifndef NO_LIBAUDIT ifneq ($(feature-libaudit), 1) msg := $(warning No libaudit.h found, disables 'trace' tool, please install audit-libs-devel or libaudit-dev); diff --git a/tools/perf/util/Build b/tools/perf/util/Build index ea4ac03..2e21529 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -97,7 +97,8 @@ libperf-$(CONFIG_DWARF) += probe-finder.o libperf-$(CONFIG_DWARF) += dwarf-aux.o libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o -libperf-$(CONFIG_LIBUNWIND) += unwind-libunwind.o +libperf-$(CONFIG_LOCAL_LIBUNWIND)+= unwind-libunwind.o +libperf-$(CONFIG_LIBUNWIND) += unwind-libunwind_common.o libperf-$(CONFIG_LIBBABELTRACE) += data-convert-bt.o diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index e0cdcf7..cf60db1 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c @@ -41,9 +41,6 @@ struct thread *thread__new(pid_t pid, pid_t tid) thread->cpu = -1; INIT_LIST_HEAD(&thread->comm_list); - if (unwind__prepare_access(thread) < 0) - goto err_thread; - comm_str = malloc(32); if (!comm_str) goto err_thread; @@ -57,6 +54,9 @@ struct thread *thread__new(pid_t pid, pid_t tid) list_add(&comm->list, &thread->comm_list); atomic_set(&thread->refcnt, 1); RB_CLEAR_NODE(&thread->rb_node); +#ifdef HAVE_LIBUNWIND_SUPPORT + register_null_unwind_libunwind_ops(thread); +#endif } return thread; @@ -82,7 +82,9 @@ void thread__delete(struct thread *thread) list_del(&comm->list); comm__free(comm); } - unwind__finish_access(thread); +#ifdef HAVE_LIBUNWIND_SUPPORT + thread->unwind_libunwind_ops->finish_access(thread); +#endif free(thread); } @@ -144,8 +146,10 @@ int __thread__set_comm(struct thread *thread, const char *str, u64 timestamp, return -ENOMEM; list_add(&new->list, &thread->comm_list); +#ifdef HAVE_LIBUNWIND_SUPPORT if (exec) - unwind__flush_access(thread); + thread->unwind_libunwind_ops->flush_access(thread); +#endif } thread->comm_set = true; @@ -208,14 +212,27 @@ void thre
[PATCH 1/8] perf tools: Omit DWARF judgement when recording dwarf callchain
There's no need for dwarf support when perf recording with callchain. Signed-off-by: He Kuang --- tools/perf/util/util.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index b7766c5..e5ebfd4 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c @@ -471,7 +471,6 @@ int parse_callchain_record(const char *arg, struct callchain_param *param) "needed for --call-graph fp\n"); break; -#ifdef HAVE_DWARF_UNWIND_SUPPORT /* Dwarf style */ } else if (!strncmp(name, "dwarf", sizeof("dwarf"))) { const unsigned long default_stack_dump_size = 8192; @@ -487,7 +486,6 @@ int parse_callchain_record(const char *arg, struct callchain_param *param) ret = get_stack_size(tok, &size); param->dump_size = size; } -#endif /* HAVE_DWARF_UNWIND_SUPPORT */ } else if (!strncmp(name, "lbr", sizeof("lbr"))) { if (!strtok_r(NULL, ",", &saveptr)) { param->record_mode = CALLCHAIN_LBR; -- 1.8.5.2
[PATCH 5/8] perf tools: Promote proper messages for cross-platform unwind
Currently, perf script uses host unwind methods to parse perf.data callchain info regardless of the target architecture. So we get wrong result and no promotion when unwinding callchains of x86(32bit) on x86(64bit) machine. This patch shows proper error messages when we do remote unwind x86(32bit) on other machines. Same thing for other platforms will be added in next patches. Signed-off-by: He Kuang --- tools/perf/config/Makefile | 6 ++ tools/perf/util/symbol-elf.c | 16 +++ tools/perf/util/symbol.c | 49 tools/perf/util/symbol.h | 2 ++ tools/perf/util/thread.c | 31 5 files changed, 104 insertions(+) diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index 1e46277..a86b864 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile @@ -345,6 +345,12 @@ ifeq ($(ARCH),powerpc) endif ifndef NO_LIBUNWIND + ifeq ($(feature-libunwind-x86), 1) +LIBUNWIND_LIBS += -lunwind-x86 +$(call detected,CONFIG_LIBUNWIND_X86) +CFLAGS += -DHAVE_LIBUNWIND_X86_SUPPORT + endif + ifneq ($(feature-libunwind), 1) msg := $(warning No libunwind found. Please install libunwind-dev[el] >= 1.1 and/or set LIBUNWIND_DIR); NO_LIBUNWIND := 1 diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index 3f9d679..9f290b9 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c @@ -636,6 +636,22 @@ bool __weak elf__needs_adjust_symbols(GElf_Ehdr ehdr) return ehdr.e_type == ET_EXEC || ehdr.e_type == ET_REL; } +int elf_is_64_bit(char *name) +{ + Elf *elf; + int fd; + + fd = open(name, O_RDONLY); + if (fd < 0) + return -1; + + elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); + if (elf == NULL) + return -1; + + return (gelf_getclass(elf) == ELFCLASS64); +} + int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name, enum dso_binary_type type) { diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 93f348f..c33aa5a 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -1395,6 +1395,55 @@ static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod, } } +int dso_is_64_bit(struct dso *dso, struct map *map) +{ + char *name; + u_int i; + bool kmod; + char *root_dir = (char *) ""; + struct machine *machine; + + if (map->groups && map->groups->machine) + machine = map->groups->machine; + else + machine = NULL; + + if (machine) + root_dir = machine->root_dir; + + name = malloc(PATH_MAX); + if (!name) + return -1; + + kmod = dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE || + dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP || + dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE || + dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE_COMP; + + /* +* Iterate over candidate debug images. +* Keep track of "interesting" ones (those which have a symtab, dynsym, +* and/or opd section) for processing. +*/ + for (i = 0; i < DSO_BINARY_TYPE__SYMTAB_CNT; i++) { + enum dso_binary_type symtab_type = binary_type_symtab[i]; + + if (!dso__is_compatible_symtab_type(dso, kmod, symtab_type)) + continue; + + if (dso__read_binary_type_filename(dso, symtab_type, + root_dir, name, PATH_MAX)) + continue; + + if (!is_regular_file(name)) + continue; + + return elf_is_64_bit(name); + } + + return -1; +} + int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) { char *name; diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 4e6910e..d33fbf4 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -308,6 +308,8 @@ int setup_list(struct strlist **list, const char *list_str, const char *list_name); int setup_intlist(struct intlist **list, const char *list_str, const char *list_name); +int elf_is_64_bit(char *name); +int dso_is_64_bit(struct dso *dso, struct map *map); #ifdef HAVE_LIBELF_SUPPORT bool elf__needs_adjust_symbols(GElf_Ehdr ehdr); diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index dfd00c6..e0cdcf7 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c @@ -184,8 +184,39 @@ size_t thread__fprintf(struct thread *thread, FILE *fp) void thread__insert_map(struct thread *thread, struct map *map) { + char * __maybe_unused arch; + int __maybe_unused is_64_bi
[PATCH 8/8] perf callchain: Support aarch64 cross-platform
Support aarch64 cross platform callchain unwind. Signed-off-by: He Kuang --- .../perf/arch/arm64/include/libunwind/libunwind-arch.h | 18 ++ tools/perf/arch/arm64/util/unwind-libunwind.c | 5 - tools/perf/config/Makefile | 12 tools/perf/util/Build | 4 tools/perf/util/thread.c | 12 tools/perf/util/unwind.h | 3 +++ 6 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 tools/perf/arch/arm64/include/libunwind/libunwind-arch.h diff --git a/tools/perf/arch/arm64/include/libunwind/libunwind-arch.h b/tools/perf/arch/arm64/include/libunwind/libunwind-arch.h new file mode 100644 index 000..7bc8a00 --- /dev/null +++ b/tools/perf/arch/arm64/include/libunwind/libunwind-arch.h @@ -0,0 +1,18 @@ +#ifndef _LIBUNWIND_ARCH_H +#define _LIBUNWIND_ARCH_H + +#include +#include <../perf_regs.h> +#include <../../../../../../arch/arm64/include/uapi/asm/perf_regs.h> + +#define LIBUNWIND_AARCH64 +int libunwind__aarch64_reg_id(int regnum); + +#include <../../../arm64/util/unwind-libunwind.c> + +#define LIBUNWIND__ARCH_REG_ID libunwind__aarch64_reg_id + +#define UNWT_PREFIXUNW_PASTE(UNW_PASTE(_U, aarch64), _) +#define UNWT_OBJ(fn) UNW_PASTE(UNWT_PREFIX, fn) + +#endif /* _LIBUNWIND_ARCH_H */ diff --git a/tools/perf/arch/arm64/util/unwind-libunwind.c b/tools/perf/arch/arm64/util/unwind-libunwind.c index a87afa9..5b557a5 100644 --- a/tools/perf/arch/arm64/util/unwind-libunwind.c +++ b/tools/perf/arch/arm64/util/unwind-libunwind.c @@ -1,11 +1,14 @@ #include -#include #include "perf_regs.h" #include "../../util/unwind.h" #include "../../util/debug.h" +#ifndef LIBUNWIND_AARCH64 int libunwind__arch_reg_id(int regnum) +#else +int libunwind__aarch64_reg_id(int regnum) +#endif { switch (regnum) { case UNW_AARCH64_X0: diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index 16f14b1..c1bfc5e 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile @@ -353,6 +353,18 @@ ifndef NO_LIBUNWIND have_libunwind = 1 endif + ifeq ($(feature-libunwind-aarch64), 1) +$(call detected,CONFIG_LIBUNWIND_AARCH64) +CFLAGS += -DHAVE_LIBUNWIND_AARCH64_SUPPORT +LDFLAGS += -lunwind -lunwind-aarch64 +have_libunwind = 1 +$(call feature_check,libunwind-debug-frame-aarch64) +ifneq ($(feature-libunwind-debug-frame-aarch64), 1) + msg := $(warning No debug_frame support found in libunwind-aarch64); + CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME_AARCH64 +endif + endif + ifneq ($(feature-libunwind), 1) msg := $(warning No libunwind found. Please install libunwind-dev[el] >= 1.1 and/or set LIBUNWIND_DIR); NO_LOCAL_LIBUNWIND := 1 diff --git a/tools/perf/util/Build b/tools/perf/util/Build index 2dd3939..10e42ad 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -102,10 +102,14 @@ libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o libperf-$(CONFIG_LOCAL_LIBUNWIND)+= unwind-libunwind.o libperf-$(CONFIG_LIBUNWIND) += unwind-libunwind_common.o libperf-$(CONFIG_LIBUNWIND_X86) += unwind-libunwind_x86_32.o +libperf-$(CONFIG_LIBUNWIND_AARCH64) += unwind-libunwind_arm64.o $(OUTPUT)util/unwind-libunwind_x86_32.o: util/unwind-libunwind.c arch/x86/util/unwind-libunwind.c $(QUIET_CC)$(CC) $(CFLAGS) -DARCH_UNWIND_LIBUNWIND -Iarch/x86/include/libunwind -c -o $@ util/unwind-libunwind.c +$(OUTPUT)util/unwind-libunwind_arm64.o: util/unwind-libunwind.c arch/arm64/util/unwind-libunwind.c + $(QUIET_CC)$(CC) $(CFLAGS) -DARCH_UNWIND_LIBUNWIND -Iarch/arm64/include/libunwind -c -o $@ util/unwind-libunwind.c + libperf-$(CONFIG_LIBBABELTRACE) += data-convert-bt.o libperf-y += scripting-engines/ diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 2b93856..ba3e597 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c @@ -221,6 +221,18 @@ void thread__insert_map(struct thread *thread, struct map *map) goto err; #endif } + } else if (!strcmp(arch, "aarch64") || !strncmp(arch, "arm", 3)) { + pr_debug("Thread map is ARM, 64bit is %d, dso=%s\n", +is_64_bit, map->dso->name); + if (is_64_bit) { +#ifdef HAVE_LIBUNWIND_AARCH64_SUPPORT + register_unwind_libunwind_ops( + &_Uaarch64_unwind_libunwind_ops, thread); +#else + register_null_unwind_libunwind_ops(thread); + goto err; +#endif + } } else { register_local_unwind_libunwind_ops(thread); } diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h index 98d40bd..d215717 100644 --- a/t
[PATCH 7/8] perf callchain: Support x86 target platform
Support x86(32bit) cross platform callchain unwind. Signed-off-by: He Kuang --- .../arch/x86/include/libunwind/libunwind-arch.h| 18 ++ tools/perf/arch/x86/util/unwind-libunwind.c| 42 ++ tools/perf/util/Build | 6 tools/perf/util/thread.c | 10 +++--- tools/perf/util/unwind-libunwind.c | 2 +- tools/perf/util/unwind.h | 5 +++ 6 files changed, 77 insertions(+), 6 deletions(-) create mode 100644 tools/perf/arch/x86/include/libunwind/libunwind-arch.h diff --git a/tools/perf/arch/x86/include/libunwind/libunwind-arch.h b/tools/perf/arch/x86/include/libunwind/libunwind-arch.h new file mode 100644 index 000..265f14d --- /dev/null +++ b/tools/perf/arch/x86/include/libunwind/libunwind-arch.h @@ -0,0 +1,18 @@ +#ifndef _LIBUNWIND_ARCH_H +#define _LIBUNWIND_ARCH_H + +#include +#include <../perf_regs.h> +#include <../../../../../../arch/x86/include/uapi/asm/perf_regs.h> + +#define LIBUNWIND_X86_32 +int libunwind__x86_reg_id(int regnum); + +#include <../../../x86/util/unwind-libunwind.c> + +#define LIBUNWIND__ARCH_REG_ID libunwind__x86_reg_id + +#define UNWT_PREFIXUNW_PASTE(UNW_PASTE(_U, x86), _) +#define UNWT_OBJ(fn) UNW_PASTE(UNWT_PREFIX, fn) + +#endif /* _LIBUNWIND_ARCH_H */ diff --git a/tools/perf/arch/x86/util/unwind-libunwind.c b/tools/perf/arch/x86/util/unwind-libunwind.c index db25e93..d422fbf 100644 --- a/tools/perf/arch/x86/util/unwind-libunwind.c +++ b/tools/perf/arch/x86/util/unwind-libunwind.c @@ -5,6 +5,7 @@ #include "../../util/unwind.h" #include "../../util/debug.h" +#ifndef LIBUNWIND_X86_32 #ifdef HAVE_ARCH_X86_64_SUPPORT int libunwind__arch_reg_id(int regnum) { @@ -110,3 +111,44 @@ int libunwind__arch_reg_id(int regnum) return id; } #endif /* HAVE_ARCH_X86_64_SUPPORT */ +#else +int libunwind__x86_reg_id(int regnum) +{ + int id; + + switch (regnum) { + case UNW_X86_EAX: + id = PERF_REG_X86_AX; + break; + case UNW_X86_EDX: + id = PERF_REG_X86_DX; + break; + case UNW_X86_ECX: + id = PERF_REG_X86_CX; + break; + case UNW_X86_EBX: + id = PERF_REG_X86_BX; + break; + case UNW_X86_ESI: + id = PERF_REG_X86_SI; + break; + case UNW_X86_EDI: + id = PERF_REG_X86_DI; + break; + case UNW_X86_EBP: + id = PERF_REG_X86_BP; + break; + case UNW_X86_ESP: + id = PERF_REG_X86_SP; + break; + case UNW_X86_EIP: + id = PERF_REG_X86_IP; + break; + default: + pr_err("unwind: invalid reg id %d\n", regnum); + return -EINVAL; + } + + return id; +} +#endif /* LIBUNWIND_X86_32 */ diff --git a/tools/perf/util/Build b/tools/perf/util/Build index 2e21529..2dd3939 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -1,3 +1,5 @@ +include ../scripts/Makefile.include + libperf-y += alias.o libperf-y += annotate.o libperf-y += build-id.o @@ -99,6 +101,10 @@ libperf-$(CONFIG_DWARF) += dwarf-aux.o libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o libperf-$(CONFIG_LOCAL_LIBUNWIND)+= unwind-libunwind.o libperf-$(CONFIG_LIBUNWIND) += unwind-libunwind_common.o +libperf-$(CONFIG_LIBUNWIND_X86) += unwind-libunwind_x86_32.o + +$(OUTPUT)util/unwind-libunwind_x86_32.o: util/unwind-libunwind.c arch/x86/util/unwind-libunwind.c + $(QUIET_CC)$(CC) $(CFLAGS) -DARCH_UNWIND_LIBUNWIND -Iarch/x86/include/libunwind -c -o $@ util/unwind-libunwind.c libperf-$(CONFIG_LIBBABELTRACE) += data-convert-bt.o diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index cf60db1..2b93856 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c @@ -214,12 +214,12 @@ void thread__insert_map(struct thread *thread, struct map *map) pr_debug("Thread map is X86, 64bit is %d\n", is_64_bit); if (!is_64_bit) { #ifdef HAVE_LIBUNWIND_X86_SUPPORT - pr_err("target platform=%s is not implemented!\n", - arch); + register_unwind_libunwind_ops( + &_Ux86_unwind_libunwind_ops, thread); #else - pr_err("target platform=%s is not supported!\n", arch); -#endif + register_null_unwind_libunwind_ops(thread); goto err; +#endif } } else { register_local_unwind_libunwind_ops(thread); @@ -231,7 +231,7 @@ void thread__insert_map(struct thread *thread, struct map *map) return; err: __maybe_unused - register_null_unwind_libunwind_ops(thread); + pr_err
[PATCH 3/8] perf build: Add build-test for libunwind cross-platforms support
Currently only test for local libunwind. We should check all supported platforms so we can use them to parse perf.data with callchain info on different machines. Signed-off-by: He Kuang --- tools/build/Makefile.feature | 8 tools/build/feature/Makefile | 16 tools/build/feature/test-libunwind-aarch64.c | 26 ++ tools/build/feature/test-libunwind-arm.c | 27 +++ tools/build/feature/test-libunwind-x86.c | 27 +++ tools/build/feature/test-libunwind-x86_64.c | 27 +++ 6 files changed, 131 insertions(+) create mode 100644 tools/build/feature/test-libunwind-aarch64.c create mode 100644 tools/build/feature/test-libunwind-arm.c create mode 100644 tools/build/feature/test-libunwind-x86.c create mode 100644 tools/build/feature/test-libunwind-x86_64.c diff --git a/tools/build/Makefile.feature b/tools/build/Makefile.feature index 9f87861..139e99c 100644 --- a/tools/build/Makefile.feature +++ b/tools/build/Makefile.feature @@ -49,6 +49,10 @@ FEATURE_TESTS_BASIC := \ libslang\ libcrypto \ libunwind \ + libunwind-x86 \ + libunwind-x86_64\ + libunwind-arm \ + libunwind-aarch64 \ pthread-attr-setaffinity-np \ stackprotector-all \ timerfd \ @@ -92,6 +96,10 @@ FEATURE_DISPLAY ?= \ libslang\ libcrypto \ libunwind \ + libunwind-x86 \ + libunwind-x86_64\ + libunwind-arm \ + libunwind-aarch64 \ libdw-dwarf-unwind \ zlib\ lzma\ diff --git a/tools/build/feature/Makefile b/tools/build/feature/Makefile index 4ae94db..f4fe3bc 100644 --- a/tools/build/feature/Makefile +++ b/tools/build/feature/Makefile @@ -27,6 +27,10 @@ FILES= \ test-libcrypto.bin \ test-libunwind.bin \ test-libunwind-debug-frame.bin \ + test-libunwind-x86.bin \ + test-libunwind-x86_64.bin \ + test-libunwind-arm.bin \ + test-libunwind-aarch64.bin \ test-pthread-attr-setaffinity-np.bin\ test-stackprotector-all.bin \ test-timerfd.bin\ @@ -103,6 +107,18 @@ $(OUTPUT)test-libunwind.bin: $(OUTPUT)test-libunwind-debug-frame.bin: $(BUILD) -lelf +$(OUTPUT)test-libunwind-x86.bin: + $(BUILD) -lelf -lunwind-x86 + +$(OUTPUT)test-libunwind-x86_64.bin: + $(BUILD) -lelf -lunwind-x86_64 + +$(OUTPUT)test-libunwind-arm.bin: + $(BUILD) -lelf -lunwind-arm + +$(OUTPUT)test-libunwind-aarch64.bin: + $(BUILD) -lelf -lunwind-aarch64 + $(OUTPUT)test-libaudit.bin: $(BUILD) -laudit diff --git a/tools/build/feature/test-libunwind-aarch64.c b/tools/build/feature/test-libunwind-aarch64.c new file mode 100644 index 000..fc03fb6 --- /dev/null +++ b/tools/build/feature/test-libunwind-aarch64.c @@ -0,0 +1,26 @@ +#include +#include + +extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, + unw_word_t ip, + unw_dyn_info_t *di, + unw_proc_info_t *pi, + int need_unwind_info, void *arg); + +#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table) + +static unw_accessors_t accessors; + +int main(void) +{ + unw_addr_space_t addr_space; + + addr_space = unw_create_addr_space(&accessors, 0); + if (addr_space) + return 0; + + unw_init_remote(NULL, addr_space, NULL); + dwarf_search_unwind_table(addr_space, 0, NULL, NULL, 0, NULL); + + return 0; +} diff --git a/tools/build/feature/test-libunwind-arm.c b/tools/build/feature/test-libunwind-arm.c new file mode 100644 index 000..632d95e --- /dev/null +++ b/tools/build/feature/test-libunwind-arm.c @@ -0,0 +1,27 @@ +#include +#include + +extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, + unw_word_t ip, + unw_dyn_info_t *di, + unw_proc_info_t *pi, + int need_unwind_info, void *arg); + + +#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table) + +static unw_accessors_t accessors; + +int main(void) +{ + unw_addr_space_t addr_s
[PATCH 2/8] perf script: Add options for custom vdso name
When unwinding callchain on different machine, vdso info should be provided so the unwind process won't be interrupted if address fell into vdso region. Signed-off-by: He Kuang --- tools/perf/builtin-script.c | 2 ++ tools/perf/util/dso.c | 7 +++ tools/perf/util/dso.h | 1 + tools/perf/util/symbol.c| 1 + tools/perf/util/symbol.h| 1 + 5 files changed, 12 insertions(+) diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 8f6ab2a..c88b547 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -2001,6 +2001,8 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) "file", "vmlinux pathname"), OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name, "file", "kallsyms pathname"), + OPT_STRING(0, "vdso", &symbol_conf.vdso_name, + "file", "vdso pathname"), OPT_BOOLEAN('G', "hide-call-graph", &no_callchain, "When printing symbols do not display call chain"), OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c index 8e639543..344db10 100644 --- a/tools/perf/util/dso.c +++ b/tools/perf/util/dso.c @@ -21,6 +21,7 @@ char dso__symtab_origin(const struct dso *dso) [DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO] = 'o', [DSO_BINARY_TYPE__BUILDID_DEBUGINFO]= 'b', [DSO_BINARY_TYPE__SYSTEM_PATH_DSO] = 'd', + [DSO_BINARY_TYPE__SYSTEM_PATH_DSO_CUSTOM] = 'r', [DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE] = 'K', [DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP] = 'm', [DSO_BINARY_TYPE__GUEST_KALLSYMS] = 'g', @@ -113,6 +114,11 @@ int dso__read_binary_type_filename(const struct dso *dso, build_id_hex, build_id_hex + 2); break; + case DSO_BINARY_TYPE__SYSTEM_PATH_DSO_CUSTOM: + { + snprintf(filename, size, "%s", symbol_conf.vdso_name); + break; + } case DSO_BINARY_TYPE__VMLINUX: case DSO_BINARY_TYPE__GUEST_VMLINUX: case DSO_BINARY_TYPE__SYSTEM_PATH_DSO: @@ -487,6 +493,7 @@ static void try_to_open_dso(struct dso *dso, struct machine *machine) enum dso_binary_type binary_type_data[] = { DSO_BINARY_TYPE__BUILD_ID_CACHE, DSO_BINARY_TYPE__SYSTEM_PATH_DSO, + DSO_BINARY_TYPE__SYSTEM_PATH_DSO_CUSTOM, DSO_BINARY_TYPE__NOT_FOUND, }; int i = 0; diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h index 0953280..f55ce5b 100644 --- a/tools/perf/util/dso.h +++ b/tools/perf/util/dso.h @@ -23,6 +23,7 @@ enum dso_binary_type { DSO_BINARY_TYPE__UBUNTU_DEBUGINFO, DSO_BINARY_TYPE__BUILDID_DEBUGINFO, DSO_BINARY_TYPE__SYSTEM_PATH_DSO, + DSO_BINARY_TYPE__SYSTEM_PATH_DSO_CUSTOM, DSO_BINARY_TYPE__GUEST_KMODULE, DSO_BINARY_TYPE__GUEST_KMODULE_COMP, DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE, diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index e7588dc..93f348f 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -1359,6 +1359,7 @@ static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod, case DSO_BINARY_TYPE__JAVA_JIT: case DSO_BINARY_TYPE__DEBUGLINK: case DSO_BINARY_TYPE__SYSTEM_PATH_DSO: + case DSO_BINARY_TYPE__SYSTEM_PATH_DSO_CUSTOM: case DSO_BINARY_TYPE__FEDORA_DEBUGINFO: case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO: case DSO_BINARY_TYPE__BUILDID_DEBUGINFO: diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index c8b7544..4e6910e 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -114,6 +114,7 @@ struct symbol_conf { report_hierarchy; const char *vmlinux_name, *kallsyms_name, + *vdso_name, *source_prefix, *field_sep; const char *default_guest_vmlinux_name, -- 1.8.5.2
[PATCH v2 5/9] perf tools: Add methods to test dso is 64-bit or 32-bit
32-bit programs can be run on 64-bit machines, so we should choose unwind methods according to 'thread->map' instead of the host architecture. This patch adds methods to test whether a dso is 64-bit or 32-bit by the class info in elf. Signed-off-by: He Kuang --- tools/perf/util/symbol-elf.c | 16 +++ tools/perf/util/symbol.c | 49 tools/perf/util/symbol.h | 2 ++ 3 files changed, 67 insertions(+) diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index 3f9d679..9f290b9 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c @@ -636,6 +636,22 @@ bool __weak elf__needs_adjust_symbols(GElf_Ehdr ehdr) return ehdr.e_type == ET_EXEC || ehdr.e_type == ET_REL; } +int elf_is_64_bit(char *name) +{ + Elf *elf; + int fd; + + fd = open(name, O_RDONLY); + if (fd < 0) + return -1; + + elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); + if (elf == NULL) + return -1; + + return (gelf_getclass(elf) == ELFCLASS64); +} + int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name, enum dso_binary_type type) { diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 4630751..592bf8c 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -1395,6 +1395,55 @@ static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod, } } +int dso_is_64_bit(struct dso *dso, struct map *map) +{ + char *name; + u_int i; + bool kmod; + char *root_dir = (char *) ""; + struct machine *machine; + + if (map->groups && map->groups->machine) + machine = map->groups->machine; + else + machine = NULL; + + if (machine) + root_dir = machine->root_dir; + + name = malloc(PATH_MAX); + if (!name) + return -1; + + kmod = dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE || + dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP || + dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE || + dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE_COMP; + + /* +* Iterate over candidate debug images. +* Keep track of "interesting" ones (those which have a symtab, dynsym, +* and/or opd section) for processing. +*/ + for (i = 0; i < DSO_BINARY_TYPE__SYMTAB_CNT; i++) { + enum dso_binary_type symtab_type = binary_type_symtab[i]; + + if (!dso__is_compatible_symtab_type(dso, kmod, symtab_type)) + continue; + + if (dso__read_binary_type_filename(dso, symtab_type, + root_dir, name, PATH_MAX)) + continue; + + if (!is_regular_file(name)) + continue; + + return elf_is_64_bit(name); + } + + return -1; +} + int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) { char *name; diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 4e6910e..d33fbf4 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -308,6 +308,8 @@ int setup_list(struct strlist **list, const char *list_str, const char *list_name); int setup_intlist(struct intlist **list, const char *list_str, const char *list_name); +int elf_is_64_bit(char *name); +int dso_is_64_bit(struct dso *dso, struct map *map); #ifdef HAVE_LIBELF_SUPPORT bool elf__needs_adjust_symbols(GElf_Ehdr ehdr); -- 1.8.5.2
[PATCH v2 6/9] perf tools: Promote proper messages for cross-platform unwind
Currently, perf script uses host unwind methods to parse perf.data callchain info regardless of the target architecture. So we get wrong result and no promotion when unwinding callchains of x86(32-bit) on x86(64-bit) machine. This patch shows proper error messages when we do remote unwind x86(32-bit) on other machines. Same thing for other platforms will be added in next patches. Signed-off-by: He Kuang --- tools/perf/config/Makefile | 6 ++ tools/perf/util/thread.c | 2 ++ tools/perf/util/unwind-libunwind.c | 32 tools/perf/util/unwind.h | 5 + 4 files changed, 45 insertions(+) diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index 1e46277..a86b864 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile @@ -345,6 +345,12 @@ ifeq ($(ARCH),powerpc) endif ifndef NO_LIBUNWIND + ifeq ($(feature-libunwind-x86), 1) +LIBUNWIND_LIBS += -lunwind-x86 +$(call detected,CONFIG_LIBUNWIND_X86) +CFLAGS += -DHAVE_LIBUNWIND_X86_SUPPORT + endif + ifneq ($(feature-libunwind), 1) msg := $(warning No libunwind found. Please install libunwind-dev[el] >= 1.1 and/or set LIBUNWIND_DIR); NO_LIBUNWIND := 1 diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index dfd00c6..244c4f6 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c @@ -186,6 +186,8 @@ void thread__insert_map(struct thread *thread, struct map *map) { map_groups__fixup_overlappings(thread->mg, map, stderr); map_groups__insert(thread->mg, map); + + unwind__get_arch(thread, map); } static int thread__clone_map_groups(struct thread *thread, diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c index 63687d3..b6eb317 100644 --- a/tools/perf/util/unwind-libunwind.c +++ b/tools/perf/util/unwind-libunwind.c @@ -680,3 +680,35 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg, return get_entries(&ui, cb, arg, max_stack); } + +void unwind__get_arch(struct thread *thread, struct map *map) +{ + char *arch; + int is_64_bit; + + if (!thread->mg->machine->env) + return; + + is_64_bit = dso_is_64_bit(map->dso, map); + if (is_64_bit < 0) + return; + + if (thread->addr_space) + pr_debug("Thread map already set, 64bit is %d, dso=%s\n", +is_64_bit, map->dso->name); + + arch = thread->mg->machine->env->arch; + + if (!strcmp(arch, "x86_64") + || !strcmp(arch, "x86") + || !strcmp(arch, "i686")) { + pr_debug("Thread map is X86, 64bit is %d\n", is_64_bit); + if (!is_64_bit) +#ifdef HAVE_LIBUNWIND_X86_SUPPORT + pr_err("target platform=%s is not implemented!\n", + arch); +#else + pr_err("target platform=%s is not supported!\n", arch); +#endif + } +} diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h index 12790cf..889d630 100644 --- a/tools/perf/util/unwind.h +++ b/tools/perf/util/unwind.h @@ -24,6 +24,7 @@ int libunwind__arch_reg_id(int regnum); int unwind__prepare_access(struct thread *thread); void unwind__flush_access(struct thread *thread); void unwind__finish_access(struct thread *thread); +void unwind__get_arch(struct thread *thread, struct map *map); #else static inline int unwind__prepare_access(struct thread *thread __maybe_unused) { @@ -32,6 +33,8 @@ static inline int unwind__prepare_access(struct thread *thread __maybe_unused) static inline void unwind__flush_access(struct thread *thread __maybe_unused) {} static inline void unwind__finish_access(struct thread *thread __maybe_unused) {} +static inline void unwind__get_arch(struct thread *thread __maybe_unused, + struct map *map __maybe_unused) {} #endif #else static inline int @@ -51,5 +54,7 @@ static inline int unwind__prepare_access(struct thread *thread __maybe_unused) static inline void unwind__flush_access(struct thread *thread __maybe_unused) {} static inline void unwind__finish_access(struct thread *thread __maybe_unused) {} +static inline void unwind__get_arch(struct thread *thread __maybe_unused, + struct map *map __maybe_unused) {} #endif /* HAVE_DWARF_UNWIND_SUPPORT */ #endif /* __UNWIND_H */ -- 1.8.5.2
[PATCH v2 7/9] perf callchain: Add support for cross-platform unwind
Use thread specific unwind ops to unwind cross-platform callchains. Before this patch, unwind methods is suitable for local unwind, this patch changes the fixed methods to thread/map related. Each time a map is inserted, we find the target arch and see if this platform can be remote unwind. In this patch, we test for x86 platform and only show proper messages. The real unwind methods are not implemented, will be introduced in next patch. Common function used by both local unwind and remote unwind are separated into new file 'unwind-libunwind_common.c'. Signed-off-by: He Kuang --- tools/perf/config/Makefile| 19 +- tools/perf/util/Build | 3 +- tools/perf/util/thread.c | 5 +- tools/perf/util/thread.h | 14 - tools/perf/util/unwind-libunwind.c| 73 +++--- tools/perf/util/unwind-libunwind_common.c | 100 ++ tools/perf/util/unwind.h | 35 --- 7 files changed, 196 insertions(+), 53 deletions(-) create mode 100644 tools/perf/util/unwind-libunwind_common.c diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index a86b864..16f14b1 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile @@ -345,14 +345,24 @@ ifeq ($(ARCH),powerpc) endif ifndef NO_LIBUNWIND + have_libunwind = ifeq ($(feature-libunwind-x86), 1) -LIBUNWIND_LIBS += -lunwind-x86 $(call detected,CONFIG_LIBUNWIND_X86) CFLAGS += -DHAVE_LIBUNWIND_X86_SUPPORT +LDFLAGS += -lunwind -lunwind-x86 +have_libunwind = 1 endif ifneq ($(feature-libunwind), 1) msg := $(warning No libunwind found. Please install libunwind-dev[el] >= 1.1 and/or set LIBUNWIND_DIR); +NO_LOCAL_LIBUNWIND := 1 + else +have_libunwind = 1 +CFLAGS += -DHAVE_LIBUNWIND_LOCAL_SUPPORT +$(call detected,CONFIG_LOCAL_LIBUNWIND) + endif + + ifneq ($(have_libunwind), 1) NO_LIBUNWIND := 1 endif endif @@ -392,7 +402,7 @@ else NO_DWARF_UNWIND := 1 endif -ifndef NO_LIBUNWIND +ifndef NO_LOCAL_LIBUNWIND ifeq ($(ARCH),$(filter $(ARCH),arm arm64)) $(call feature_check,libunwind-debug-frame) ifneq ($(feature-libunwind-debug-frame), 1) @@ -403,12 +413,15 @@ ifndef NO_LIBUNWIND # non-ARM has no dwarf_find_debug_frame() function: CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME endif - CFLAGS += -DHAVE_LIBUNWIND_SUPPORT EXTLIBS += $(LIBUNWIND_LIBS) CFLAGS += $(LIBUNWIND_CFLAGS) LDFLAGS += $(LIBUNWIND_LDFLAGS) endif +ifndef NO_LIBUNWIND + CFLAGS += -DHAVE_LIBUNWIND_SUPPORT +endif + ifndef NO_LIBAUDIT ifneq ($(feature-libaudit), 1) msg := $(warning No libaudit.h found, disables 'trace' tool, please install audit-libs-devel or libaudit-dev); diff --git a/tools/perf/util/Build b/tools/perf/util/Build index ea4ac03..2e21529 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -97,7 +97,8 @@ libperf-$(CONFIG_DWARF) += probe-finder.o libperf-$(CONFIG_DWARF) += dwarf-aux.o libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o -libperf-$(CONFIG_LIBUNWIND) += unwind-libunwind.o +libperf-$(CONFIG_LOCAL_LIBUNWIND)+= unwind-libunwind.o +libperf-$(CONFIG_LIBUNWIND) += unwind-libunwind_common.o libperf-$(CONFIG_LIBBABELTRACE) += data-convert-bt.o diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 244c4f6..2274263 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c @@ -41,9 +41,6 @@ struct thread *thread__new(pid_t pid, pid_t tid) thread->cpu = -1; INIT_LIST_HEAD(&thread->comm_list); - if (unwind__prepare_access(thread) < 0) - goto err_thread; - comm_str = malloc(32); if (!comm_str) goto err_thread; @@ -57,6 +54,8 @@ struct thread *thread__new(pid_t pid, pid_t tid) list_add(&comm->list, &thread->comm_list); atomic_set(&thread->refcnt, 1); RB_CLEAR_NODE(&thread->rb_node); + + register_null_unwind_libunwind_ops(thread); } return thread; diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h index e214207..6f2d4cd 100644 --- a/tools/perf/util/thread.h +++ b/tools/perf/util/thread.h @@ -15,6 +15,17 @@ struct thread_stack; +struct unwind_entry; +typedef int (*unwind_entry_cb_t)(struct unwind_entry *entry, void *arg); +struct unwind_libunwind_ops { + int (*prepare_access)(struct thread *thread); + void (*flush_access)(struct thread *thread); + void (*finish_access)(struct thread *thread); + int (*get_entries)(unwind_entry_cb_t cb, void *arg, + struct thread *thread, + struct perf_sample *data, int max_stack); +}; + struct thread { union { struct r
[PATCH v2 9/9] perf callchain: Support aarch64 cross-platform
Support aarch64 cross platform callchain unwind. Signed-off-by: He Kuang --- .../perf/arch/arm64/include/libunwind/libunwind-arch.h | 18 ++ tools/perf/arch/arm64/util/unwind-libunwind.c | 5 - tools/perf/config/Makefile | 12 tools/perf/util/Build | 4 tools/perf/util/unwind-libunwind_common.c | 12 tools/perf/util/unwind.h | 3 +++ 6 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 tools/perf/arch/arm64/include/libunwind/libunwind-arch.h diff --git a/tools/perf/arch/arm64/include/libunwind/libunwind-arch.h b/tools/perf/arch/arm64/include/libunwind/libunwind-arch.h new file mode 100644 index 000..7bc8a00 --- /dev/null +++ b/tools/perf/arch/arm64/include/libunwind/libunwind-arch.h @@ -0,0 +1,18 @@ +#ifndef _LIBUNWIND_ARCH_H +#define _LIBUNWIND_ARCH_H + +#include +#include <../perf_regs.h> +#include <../../../../../../arch/arm64/include/uapi/asm/perf_regs.h> + +#define LIBUNWIND_AARCH64 +int libunwind__aarch64_reg_id(int regnum); + +#include <../../../arm64/util/unwind-libunwind.c> + +#define LIBUNWIND__ARCH_REG_ID libunwind__aarch64_reg_id + +#define UNWT_PREFIXUNW_PASTE(UNW_PASTE(_U, aarch64), _) +#define UNWT_OBJ(fn) UNW_PASTE(UNWT_PREFIX, fn) + +#endif /* _LIBUNWIND_ARCH_H */ diff --git a/tools/perf/arch/arm64/util/unwind-libunwind.c b/tools/perf/arch/arm64/util/unwind-libunwind.c index a87afa9..5b557a5 100644 --- a/tools/perf/arch/arm64/util/unwind-libunwind.c +++ b/tools/perf/arch/arm64/util/unwind-libunwind.c @@ -1,11 +1,14 @@ #include -#include #include "perf_regs.h" #include "../../util/unwind.h" #include "../../util/debug.h" +#ifndef LIBUNWIND_AARCH64 int libunwind__arch_reg_id(int regnum) +#else +int libunwind__aarch64_reg_id(int regnum) +#endif { switch (regnum) { case UNW_AARCH64_X0: diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index 16f14b1..c1bfc5e 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile @@ -353,6 +353,18 @@ ifndef NO_LIBUNWIND have_libunwind = 1 endif + ifeq ($(feature-libunwind-aarch64), 1) +$(call detected,CONFIG_LIBUNWIND_AARCH64) +CFLAGS += -DHAVE_LIBUNWIND_AARCH64_SUPPORT +LDFLAGS += -lunwind -lunwind-aarch64 +have_libunwind = 1 +$(call feature_check,libunwind-debug-frame-aarch64) +ifneq ($(feature-libunwind-debug-frame-aarch64), 1) + msg := $(warning No debug_frame support found in libunwind-aarch64); + CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME_AARCH64 +endif + endif + ifneq ($(feature-libunwind), 1) msg := $(warning No libunwind found. Please install libunwind-dev[el] >= 1.1 and/or set LIBUNWIND_DIR); NO_LOCAL_LIBUNWIND := 1 diff --git a/tools/perf/util/Build b/tools/perf/util/Build index 2dd3939..10e42ad 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -102,10 +102,14 @@ libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o libperf-$(CONFIG_LOCAL_LIBUNWIND)+= unwind-libunwind.o libperf-$(CONFIG_LIBUNWIND) += unwind-libunwind_common.o libperf-$(CONFIG_LIBUNWIND_X86) += unwind-libunwind_x86_32.o +libperf-$(CONFIG_LIBUNWIND_AARCH64) += unwind-libunwind_arm64.o $(OUTPUT)util/unwind-libunwind_x86_32.o: util/unwind-libunwind.c arch/x86/util/unwind-libunwind.c $(QUIET_CC)$(CC) $(CFLAGS) -DARCH_UNWIND_LIBUNWIND -Iarch/x86/include/libunwind -c -o $@ util/unwind-libunwind.c +$(OUTPUT)util/unwind-libunwind_arm64.o: util/unwind-libunwind.c arch/arm64/util/unwind-libunwind.c + $(QUIET_CC)$(CC) $(CFLAGS) -DARCH_UNWIND_LIBUNWIND -Iarch/arm64/include/libunwind -c -o $@ util/unwind-libunwind.c + libperf-$(CONFIG_LIBBABELTRACE) += data-convert-bt.o libperf-y += scripting-engines/ diff --git a/tools/perf/util/unwind-libunwind_common.c b/tools/perf/util/unwind-libunwind_common.c index d0128f0..fde42b2 100644 --- a/tools/perf/util/unwind-libunwind_common.c +++ b/tools/perf/util/unwind-libunwind_common.c @@ -89,6 +89,18 @@ void unwind__get_arch(struct thread *thread, struct map *map) #endif } else use_local_unwind = 1; + } else if (!strcmp(arch, "aarch64") || !strncmp(arch, "arm", 3)) { + pr_debug("Thread map is ARM, 64bit is %d, dso=%s\n", +is_64_bit, map->dso->name); + if (is_64_bit) { +#ifdef HAVE_LIBUNWIND_AARCH64_SUPPORT + register_unwind_libunwind_ops( + &_Uaarch64_unwind_libunwind_ops, thread); +#else + register_null_unwind_libunwind_ops(thread); +#endif + } else + use_local_unwind = 1; } else { use_local_unwind = 1; } diff --git a/tools/perf/util/unwind.h b/tools/p
[PATCH v2 8/9] perf callchain: Support x86 target platform
Support x86(32-bit) cross platform callchain unwind. Signed-off-by: He Kuang --- .../arch/x86/include/libunwind/libunwind-arch.h| 18 ++ tools/perf/arch/x86/util/unwind-libunwind.c| 42 ++ tools/perf/util/Build | 6 tools/perf/util/unwind-libunwind.c | 2 +- tools/perf/util/unwind-libunwind_common.c | 7 ++-- tools/perf/util/unwind.h | 5 +++ 6 files changed, 76 insertions(+), 4 deletions(-) create mode 100644 tools/perf/arch/x86/include/libunwind/libunwind-arch.h diff --git a/tools/perf/arch/x86/include/libunwind/libunwind-arch.h b/tools/perf/arch/x86/include/libunwind/libunwind-arch.h new file mode 100644 index 000..265f14d --- /dev/null +++ b/tools/perf/arch/x86/include/libunwind/libunwind-arch.h @@ -0,0 +1,18 @@ +#ifndef _LIBUNWIND_ARCH_H +#define _LIBUNWIND_ARCH_H + +#include +#include <../perf_regs.h> +#include <../../../../../../arch/x86/include/uapi/asm/perf_regs.h> + +#define LIBUNWIND_X86_32 +int libunwind__x86_reg_id(int regnum); + +#include <../../../x86/util/unwind-libunwind.c> + +#define LIBUNWIND__ARCH_REG_ID libunwind__x86_reg_id + +#define UNWT_PREFIXUNW_PASTE(UNW_PASTE(_U, x86), _) +#define UNWT_OBJ(fn) UNW_PASTE(UNWT_PREFIX, fn) + +#endif /* _LIBUNWIND_ARCH_H */ diff --git a/tools/perf/arch/x86/util/unwind-libunwind.c b/tools/perf/arch/x86/util/unwind-libunwind.c index db25e93..d422fbf 100644 --- a/tools/perf/arch/x86/util/unwind-libunwind.c +++ b/tools/perf/arch/x86/util/unwind-libunwind.c @@ -5,6 +5,7 @@ #include "../../util/unwind.h" #include "../../util/debug.h" +#ifndef LIBUNWIND_X86_32 #ifdef HAVE_ARCH_X86_64_SUPPORT int libunwind__arch_reg_id(int regnum) { @@ -110,3 +111,44 @@ int libunwind__arch_reg_id(int regnum) return id; } #endif /* HAVE_ARCH_X86_64_SUPPORT */ +#else +int libunwind__x86_reg_id(int regnum) +{ + int id; + + switch (regnum) { + case UNW_X86_EAX: + id = PERF_REG_X86_AX; + break; + case UNW_X86_EDX: + id = PERF_REG_X86_DX; + break; + case UNW_X86_ECX: + id = PERF_REG_X86_CX; + break; + case UNW_X86_EBX: + id = PERF_REG_X86_BX; + break; + case UNW_X86_ESI: + id = PERF_REG_X86_SI; + break; + case UNW_X86_EDI: + id = PERF_REG_X86_DI; + break; + case UNW_X86_EBP: + id = PERF_REG_X86_BP; + break; + case UNW_X86_ESP: + id = PERF_REG_X86_SP; + break; + case UNW_X86_EIP: + id = PERF_REG_X86_IP; + break; + default: + pr_err("unwind: invalid reg id %d\n", regnum); + return -EINVAL; + } + + return id; +} +#endif /* LIBUNWIND_X86_32 */ diff --git a/tools/perf/util/Build b/tools/perf/util/Build index 2e21529..2dd3939 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -1,3 +1,5 @@ +include ../scripts/Makefile.include + libperf-y += alias.o libperf-y += annotate.o libperf-y += build-id.o @@ -99,6 +101,10 @@ libperf-$(CONFIG_DWARF) += dwarf-aux.o libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o libperf-$(CONFIG_LOCAL_LIBUNWIND)+= unwind-libunwind.o libperf-$(CONFIG_LIBUNWIND) += unwind-libunwind_common.o +libperf-$(CONFIG_LIBUNWIND_X86) += unwind-libunwind_x86_32.o + +$(OUTPUT)util/unwind-libunwind_x86_32.o: util/unwind-libunwind.c arch/x86/util/unwind-libunwind.c + $(QUIET_CC)$(CC) $(CFLAGS) -DARCH_UNWIND_LIBUNWIND -Iarch/x86/include/libunwind -c -o $@ util/unwind-libunwind.c libperf-$(CONFIG_LIBBABELTRACE) += data-convert-bt.o diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c index 2a8d24e..1844431 100644 --- a/tools/perf/util/unwind-libunwind.c +++ b/tools/perf/util/unwind-libunwind.c @@ -527,7 +527,7 @@ static int access_reg(unw_addr_space_t __maybe_unused as, return 0; } - id = libunwind__arch_reg_id(regnum); + id = LIBUNWIND__ARCH_REG_ID(regnum); if (id < 0) return -EINVAL; diff --git a/tools/perf/util/unwind-libunwind_common.c b/tools/perf/util/unwind-libunwind_common.c index 4bdd3b9..d0128f0 100644 --- a/tools/perf/util/unwind-libunwind_common.c +++ b/tools/perf/util/unwind-libunwind_common.c @@ -82,10 +82,11 @@ void unwind__get_arch(struct thread *thread, struct map *map) pr_debug("unwind: thread map is X86, 64bit is %d\n", is_64_bit); if (!is_64_bit) { #ifdef HAVE_LIBUNWIND_X86_SUPPORT - pr_err("unwind: target platform=%s is not implemented\n", - arch); -#endif + register_unwind_libunwind_ops( +
[PATCH v2 4/9] perf build: Add build-test for debug-frame on arm/arm64
Debug-frame for remote platforms is not related to the host platform, so we should test each platform separately. Signed-off-by: He Kuang --- tools/build/Makefile.feature | 4 +++- tools/build/feature/Makefile | 7 +++ tools/build/feature/test-libunwind-debug-frame-aarch64.c | 16 tools/build/feature/test-libunwind-debug-frame-arm.c | 16 4 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 tools/build/feature/test-libunwind-debug-frame-aarch64.c create mode 100644 tools/build/feature/test-libunwind-debug-frame-arm.c diff --git a/tools/build/Makefile.feature b/tools/build/Makefile.feature index 7e36e91..57c8f98 100644 --- a/tools/build/Makefile.feature +++ b/tools/build/Makefile.feature @@ -73,7 +73,9 @@ FEATURE_TESTS_EXTRA :=\ libbabeltrace \ liberty \ liberty-z \ - libunwind-debug-frame + libunwind-debug-frame \ + libunwind-debug-frame-arm \ + libunwind-debug-frame-aarch64 FEATURE_TESTS ?= $(FEATURE_TESTS_BASIC) diff --git a/tools/build/feature/Makefile b/tools/build/feature/Makefile index f4fe3bc..3d88f09 100644 --- a/tools/build/feature/Makefile +++ b/tools/build/feature/Makefile @@ -31,6 +31,8 @@ FILES=\ test-libunwind-x86_64.bin \ test-libunwind-arm.bin \ test-libunwind-aarch64.bin \ + test-libunwind-debug-frame-arm.bin \ + test-libunwind-debug-frame-aarch64.bin \ test-pthread-attr-setaffinity-np.bin\ test-stackprotector-all.bin \ test-timerfd.bin\ @@ -119,6 +121,11 @@ $(OUTPUT)test-libunwind-arm.bin: $(OUTPUT)test-libunwind-aarch64.bin: $(BUILD) -lelf -lunwind-aarch64 +$(OUTPUT)test-libunwind-debug-frame-arm.bin: + $(BUILD) -lelf -lunwind-arm + +$(OUTPUT)test-libunwind-debug-frame-aarch64.bin: + $(BUILD) -lelf -lunwind-aarch64 $(OUTPUT)test-libaudit.bin: $(BUILD) -laudit diff --git a/tools/build/feature/test-libunwind-debug-frame-aarch64.c b/tools/build/feature/test-libunwind-debug-frame-aarch64.c new file mode 100644 index 000..2284467 --- /dev/null +++ b/tools/build/feature/test-libunwind-debug-frame-aarch64.c @@ -0,0 +1,16 @@ +#include +#include + +extern int +UNW_OBJ(dwarf_find_debug_frame) (int found, unw_dyn_info_t *di_debug, +unw_word_t ip, unw_word_t segbase, +const char *obj_name, unw_word_t start, +unw_word_t end); + +#define dwarf_find_debug_frame UNW_OBJ(dwarf_find_debug_frame) + +int main(void) +{ + dwarf_find_debug_frame(0, NULL, 0, 0, NULL, 0, 0); + return 0; +} diff --git a/tools/build/feature/test-libunwind-debug-frame-arm.c b/tools/build/feature/test-libunwind-debug-frame-arm.c new file mode 100644 index 000..f988596 --- /dev/null +++ b/tools/build/feature/test-libunwind-debug-frame-arm.c @@ -0,0 +1,16 @@ +#include +#include + +extern int +UNW_OBJ(dwarf_find_debug_frame) (int found, unw_dyn_info_t *di_debug, +unw_word_t ip, unw_word_t segbase, +const char *obj_name, unw_word_t start, +unw_word_t end); + +#define dwarf_find_debug_frame UNW_OBJ(dwarf_find_debug_frame) + +int main(void) +{ + dwarf_find_debug_frame(0, NULL, 0, 0, NULL, 0, 0); + return 0; +} -- 1.8.5.2
[PATCH v2 1/9] perf tools: Omit DWARF judgement when recording dwarf callchain
There is no need to check for DWARF unwinding support when using the 'dwarf' callchain record method, as this will only ask the kernel to collect stack dumps for later DWARF CFI processing, which can be done in another machine, where the support for DWARF unwinding need to be present. Signed-off-by: He Kuang Acked-by: Jiri Olsa --- tools/perf/util/util.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index b7766c5..e5ebfd4 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c @@ -471,7 +471,6 @@ int parse_callchain_record(const char *arg, struct callchain_param *param) "needed for --call-graph fp\n"); break; -#ifdef HAVE_DWARF_UNWIND_SUPPORT /* Dwarf style */ } else if (!strncmp(name, "dwarf", sizeof("dwarf"))) { const unsigned long default_stack_dump_size = 8192; @@ -487,7 +486,6 @@ int parse_callchain_record(const char *arg, struct callchain_param *param) ret = get_stack_size(tok, &size); param->dump_size = size; } -#endif /* HAVE_DWARF_UNWIND_SUPPORT */ } else if (!strncmp(name, "lbr", sizeof("lbr"))) { if (!strtok_r(NULL, ",", &saveptr)) { param->record_mode = CALLCHAIN_LBR; -- 1.8.5.2
[PATCH v2 0/9] Add support for remote unwind
v1 url: http://thread.gmane.org/gmane.linux.kernel/2216256 Currently, perf script uses host unwind methods(local unwind) to parse perf.data callchain info regardless of the target architecture. So we get wrong result and no promotion when do remote unwind on other platforms/machines. This patchset adds build tests for the supported platforms for remote unwinding, and checks whether a dso is 32-bit or 64-bit according to elf class info for each thread to let perf use the correct remote unwind methods instead. Only x86 and aarch64 is added in this patchset to show the work flow, other platforms can be added easily. We can see the right result for unwind info on different machines, for example: perf.data recorded on i686 qemu with '-g' option and parsed on x86_64 machine. before this patchset: hello 1071 [000] 417.567832: probe:sys_close: (c1169d60) c1169d61 sys_close ([kernel.kallsyms]) c189c0d7 sysenter_past_esp ([kernel.kallsyms]) b77c8ba9 [unknown] ([vdso32]) after: hello 1071 [000] 417.567832: probe:sys_close: (c1169d60) c1169d61 sys_close ([kernel.kallsyms]) c189c0d7 sysenter_past_esp ([kernel.kallsyms]) b77c8ba9 [unknown] ([vdso32]) b76e51cc close (/lib/libc-2.22.so) 804842e fib (/tmp/hello) 804849d main (/tmp/hello) b762546e __libc_start_main (/lib/libc-2.22.so) 8048341 _start (/tmp/hello) v2: - Explain the reason why we can omit dwarf judgement when recording in commit message. - Elaborate on why we need to add a custom vdso path option, and change the type name to DSO_BINARY_TYPE__VDSO. - Hide the build tests status for cross platform unwind. - Keep generic version of libunwind-debug-frame test. - Put 32/64-bit test functions into separate patch. - Extract unwind related functions to unwind-libunwind.c and add new file for common parts used by both local and remote unwind. - Eliminate most of the ifdefs in .c file. Thanks. He Kuang (9): perf tools: Omit DWARF judgement when recording dwarf callchain perf script: Add options for custom vdso path perf build: Add build-test for libunwind cross-platforms support perf build: Add build-test for debug-frame on arm/arm64 perf tools: Add methods to test dso is 64-bit or 32-bit perf tools: Promote proper messages for cross-platform unwind perf callchain: Add support for cross-platform unwind perf callchain: Support x86 target platform perf callchain: Support aarch64 cross-platform tools/build/Makefile.feature | 8 +- tools/build/feature/Makefile | 23 + tools/build/feature/test-libunwind-aarch64.c | 26 + tools/build/feature/test-libunwind-arm.c | 27 + .../feature/test-libunwind-debug-frame-aarch64.c | 16 +++ .../build/feature/test-libunwind-debug-frame-arm.c | 16 +++ tools/build/feature/test-libunwind-x86.c | 27 + tools/build/feature/test-libunwind-x86_64.c| 27 + .../arch/arm64/include/libunwind/libunwind-arch.h | 18 tools/perf/arch/arm64/util/unwind-libunwind.c | 5 +- .../arch/x86/include/libunwind/libunwind-arch.h| 18 tools/perf/arch/x86/util/unwind-libunwind.c| 42 tools/perf/builtin-script.c| 2 + tools/perf/config/Makefile | 35 ++- tools/perf/util/Build | 13 ++- tools/perf/util/dso.c | 7 ++ tools/perf/util/dso.h | 1 + tools/perf/util/symbol-elf.c | 16 +++ tools/perf/util/symbol.c | 50 + tools/perf/util/symbol.h | 3 + tools/perf/util/thread.c | 7 +- tools/perf/util/thread.h | 14 ++- tools/perf/util/unwind-libunwind.c | 49 +++-- tools/perf/util/unwind-libunwind_common.c | 113 + tools/perf/util/unwind.h | 48 +++-- tools/perf/util/util.c | 2 - 26 files changed, 585 insertions(+), 28 deletions(-) create mode 100644 tools/build/feature/test-libunwind-aarch64.c create mode 100644 tools/build/feature/test-libunwind-arm.c create mode 100644 tools/build/feature/test-libunwind-debug-frame-aarch64.c create mode 100644 tools/build/feature/test-libunwind-debug-frame-arm.c create mode 100644 tools/build/feature/test-libunwind-x86.c create mode 100644 tools/build/feature/test-libunwind-x86_64.c create mode 100644 tools/perf/arch/arm64/include/libunwind/libunwind-arch.h create mode 100644 tools/perf/arch/x86/include/libunwind/libunwind-arch.h create mode 100644 tools/perf/util/unwind-libunwind_common.c -- 1.8.5.2
[PATCH v2 2/9] perf script: Add options for custom vdso path
When unwinding callchains on a different machine, vdso info should be provided so the unwind process won't be interrupted if address falls into vdso region. Currently, perf does try to read vdso binary in '.debug' folder, but the filename of the vdso file is generated randomly based on VDSO__TEMP_FILE_NAME template, such a filename is not reliable and users need a way to provide the path of their own vdso binary file. Signed-off-by: He Kuang --- tools/perf/builtin-script.c | 2 ++ tools/perf/util/dso.c | 7 +++ tools/perf/util/dso.h | 1 + tools/perf/util/symbol.c| 1 + tools/perf/util/symbol.h| 1 + 5 files changed, 12 insertions(+) diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 8f6ab2a..c88b547 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -2001,6 +2001,8 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) "file", "vmlinux pathname"), OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name, "file", "kallsyms pathname"), + OPT_STRING(0, "vdso", &symbol_conf.vdso_name, + "file", "vdso pathname"), OPT_BOOLEAN('G', "hide-call-graph", &no_callchain, "When printing symbols do not display call chain"), OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c index 8e639543..6ed1cce 100644 --- a/tools/perf/util/dso.c +++ b/tools/perf/util/dso.c @@ -13,6 +13,7 @@ char dso__symtab_origin(const struct dso *dso) static const char origin[] = { [DSO_BINARY_TYPE__KALLSYMS] = 'k', [DSO_BINARY_TYPE__VMLINUX] = 'v', + [DSO_BINARY_TYPE__VDSO] = 'D', [DSO_BINARY_TYPE__JAVA_JIT] = 'j', [DSO_BINARY_TYPE__DEBUGLINK]= 'l', [DSO_BINARY_TYPE__BUILD_ID_CACHE] = 'B', @@ -113,6 +114,11 @@ int dso__read_binary_type_filename(const struct dso *dso, build_id_hex, build_id_hex + 2); break; + case DSO_BINARY_TYPE__VDSO: + { + snprintf(filename, size, "%s", symbol_conf.vdso_name); + break; + } case DSO_BINARY_TYPE__VMLINUX: case DSO_BINARY_TYPE__GUEST_VMLINUX: case DSO_BINARY_TYPE__SYSTEM_PATH_DSO: @@ -487,6 +493,7 @@ static void try_to_open_dso(struct dso *dso, struct machine *machine) enum dso_binary_type binary_type_data[] = { DSO_BINARY_TYPE__BUILD_ID_CACHE, DSO_BINARY_TYPE__SYSTEM_PATH_DSO, + DSO_BINARY_TYPE__VDSO, DSO_BINARY_TYPE__NOT_FOUND, }; int i = 0; diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h index 0953280..05fac98 100644 --- a/tools/perf/util/dso.h +++ b/tools/perf/util/dso.h @@ -30,6 +30,7 @@ enum dso_binary_type { DSO_BINARY_TYPE__KCORE, DSO_BINARY_TYPE__GUEST_KCORE, DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO, + DSO_BINARY_TYPE__VDSO, DSO_BINARY_TYPE__NOT_FOUND, }; diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index e7588dc..4630751 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -1363,6 +1363,7 @@ static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod, case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO: case DSO_BINARY_TYPE__BUILDID_DEBUGINFO: case DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO: + case DSO_BINARY_TYPE__VDSO: return !kmod && dso->kernel == DSO_TYPE_USER; case DSO_BINARY_TYPE__KALLSYMS: diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index c8b7544..4e6910e 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -114,6 +114,7 @@ struct symbol_conf { report_hierarchy; const char *vmlinux_name, *kallsyms_name, + *vdso_name, *source_prefix, *field_sep; const char *default_guest_vmlinux_name, -- 1.8.5.2
[PATCH v2 3/9] perf build: Add build-test for libunwind cross-platforms support
Currently only test for local libunwind. We should check all supported platforms so we can use them to parse perf.data with callchain info on different machines. Signed-off-by: He Kuang --- tools/build/Makefile.feature | 4 tools/build/feature/Makefile | 16 tools/build/feature/test-libunwind-aarch64.c | 26 ++ tools/build/feature/test-libunwind-arm.c | 27 +++ tools/build/feature/test-libunwind-x86.c | 27 +++ tools/build/feature/test-libunwind-x86_64.c | 27 +++ 6 files changed, 127 insertions(+) create mode 100644 tools/build/feature/test-libunwind-aarch64.c create mode 100644 tools/build/feature/test-libunwind-arm.c create mode 100644 tools/build/feature/test-libunwind-x86.c create mode 100644 tools/build/feature/test-libunwind-x86_64.c diff --git a/tools/build/Makefile.feature b/tools/build/Makefile.feature index 9f87861..7e36e91 100644 --- a/tools/build/Makefile.feature +++ b/tools/build/Makefile.feature @@ -49,6 +49,10 @@ FEATURE_TESTS_BASIC := \ libslang\ libcrypto \ libunwind \ + libunwind-x86 \ + libunwind-x86_64\ + libunwind-arm \ + libunwind-aarch64 \ pthread-attr-setaffinity-np \ stackprotector-all \ timerfd \ diff --git a/tools/build/feature/Makefile b/tools/build/feature/Makefile index 4ae94db..f4fe3bc 100644 --- a/tools/build/feature/Makefile +++ b/tools/build/feature/Makefile @@ -27,6 +27,10 @@ FILES= \ test-libcrypto.bin \ test-libunwind.bin \ test-libunwind-debug-frame.bin \ + test-libunwind-x86.bin \ + test-libunwind-x86_64.bin \ + test-libunwind-arm.bin \ + test-libunwind-aarch64.bin \ test-pthread-attr-setaffinity-np.bin\ test-stackprotector-all.bin \ test-timerfd.bin\ @@ -103,6 +107,18 @@ $(OUTPUT)test-libunwind.bin: $(OUTPUT)test-libunwind-debug-frame.bin: $(BUILD) -lelf +$(OUTPUT)test-libunwind-x86.bin: + $(BUILD) -lelf -lunwind-x86 + +$(OUTPUT)test-libunwind-x86_64.bin: + $(BUILD) -lelf -lunwind-x86_64 + +$(OUTPUT)test-libunwind-arm.bin: + $(BUILD) -lelf -lunwind-arm + +$(OUTPUT)test-libunwind-aarch64.bin: + $(BUILD) -lelf -lunwind-aarch64 + $(OUTPUT)test-libaudit.bin: $(BUILD) -laudit diff --git a/tools/build/feature/test-libunwind-aarch64.c b/tools/build/feature/test-libunwind-aarch64.c new file mode 100644 index 000..fc03fb6 --- /dev/null +++ b/tools/build/feature/test-libunwind-aarch64.c @@ -0,0 +1,26 @@ +#include +#include + +extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, + unw_word_t ip, + unw_dyn_info_t *di, + unw_proc_info_t *pi, + int need_unwind_info, void *arg); + +#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table) + +static unw_accessors_t accessors; + +int main(void) +{ + unw_addr_space_t addr_space; + + addr_space = unw_create_addr_space(&accessors, 0); + if (addr_space) + return 0; + + unw_init_remote(NULL, addr_space, NULL); + dwarf_search_unwind_table(addr_space, 0, NULL, NULL, 0, NULL); + + return 0; +} diff --git a/tools/build/feature/test-libunwind-arm.c b/tools/build/feature/test-libunwind-arm.c new file mode 100644 index 000..632d95e --- /dev/null +++ b/tools/build/feature/test-libunwind-arm.c @@ -0,0 +1,27 @@ +#include +#include + +extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, + unw_word_t ip, + unw_dyn_info_t *di, + unw_proc_info_t *pi, + int need_unwind_info, void *arg); + + +#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table) + +static unw_accessors_t accessors; + +int main(void) +{ + unw_addr_space_t addr_space; + + addr_space = unw_create_addr_space(&accessors, 0); + if (addr_space) + return 0; + + unw_init_remote(NULL, addr_space, NULL); + dwarf_search_unwind_table(addr_space, 0, NULL, NULL, 0, NULL); + + return 0; +} diff --git a/tools/build/feature/test-libunwind-x86.c b/tools/build/feature/test-libunwind-x86.c new file mode 100644 index 000..3561edc --- /dev/null +++ b/tools/build/feature/test-libunwind-x86.c @@ -0,0 +1,27 @@ +
[PATCH v3 1/7] perf tools: Set vdso name to vdso[64,32] depending on platform
This is a preparation for cross-platform vdso lookup. There is a naming confusion about vdso name, vdso buildid generated by a 32-bit machine stores it with the name 'vdso', but when processing buildid on a 64-bit machine with the same 'perf.data', perf will search for vdso named as 'vdso32' and get failed. This patch uses different names when storing the buildid, i.e. vdso64 for 64-bit machine and vdso32 for 32-bit machine, and eliminates this naming confusion. Signed-off-by: He Kuang --- tools/perf/util/vdso.h | 7 ++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/vdso.h b/tools/perf/util/vdso.h index cdc4fab..45e9ef4 100644 --- a/tools/perf/util/vdso.h +++ b/tools/perf/util/vdso.h @@ -4,10 +4,15 @@ #include #include #include +#include "util.h" #define VDSO__MAP_NAME "[vdso]" -#define DSO__NAME_VDSO"[vdso]" +#if BITS_PER_LONG == 64 +#define DSO__NAME_VDSO"[vdso64]" +#else +#define DSO__NAME_VDSO"[vdso32]" +#endif #define DSO__NAME_VDSO32 "[vdso32]" #define DSO__NAME_VDSOX32 "[vdsox32]" -- 1.8.5.2
[PATCH v3 6/7] perf callchain: Support x86 target platform
Support x86(32-bit) cross platform callchain unwind. Signed-off-by: He Kuang --- .../arch/x86/include/libunwind/libunwind-arch.h| 18 ++ tools/perf/arch/x86/util/unwind-libunwind.c| 42 ++ tools/perf/util/Build | 6 tools/perf/util/unwind-libunwind.c | 2 +- tools/perf/util/unwind-libunwind_common.c | 7 ++-- tools/perf/util/unwind.h | 5 +++ 6 files changed, 76 insertions(+), 4 deletions(-) create mode 100644 tools/perf/arch/x86/include/libunwind/libunwind-arch.h diff --git a/tools/perf/arch/x86/include/libunwind/libunwind-arch.h b/tools/perf/arch/x86/include/libunwind/libunwind-arch.h new file mode 100644 index 000..265f14d --- /dev/null +++ b/tools/perf/arch/x86/include/libunwind/libunwind-arch.h @@ -0,0 +1,18 @@ +#ifndef _LIBUNWIND_ARCH_H +#define _LIBUNWIND_ARCH_H + +#include +#include <../perf_regs.h> +#include <../../../../../../arch/x86/include/uapi/asm/perf_regs.h> + +#define LIBUNWIND_X86_32 +int libunwind__x86_reg_id(int regnum); + +#include <../../../x86/util/unwind-libunwind.c> + +#define LIBUNWIND__ARCH_REG_ID libunwind__x86_reg_id + +#define UNWT_PREFIXUNW_PASTE(UNW_PASTE(_U, x86), _) +#define UNWT_OBJ(fn) UNW_PASTE(UNWT_PREFIX, fn) + +#endif /* _LIBUNWIND_ARCH_H */ diff --git a/tools/perf/arch/x86/util/unwind-libunwind.c b/tools/perf/arch/x86/util/unwind-libunwind.c index db25e93..d422fbf 100644 --- a/tools/perf/arch/x86/util/unwind-libunwind.c +++ b/tools/perf/arch/x86/util/unwind-libunwind.c @@ -5,6 +5,7 @@ #include "../../util/unwind.h" #include "../../util/debug.h" +#ifndef LIBUNWIND_X86_32 #ifdef HAVE_ARCH_X86_64_SUPPORT int libunwind__arch_reg_id(int regnum) { @@ -110,3 +111,44 @@ int libunwind__arch_reg_id(int regnum) return id; } #endif /* HAVE_ARCH_X86_64_SUPPORT */ +#else +int libunwind__x86_reg_id(int regnum) +{ + int id; + + switch (regnum) { + case UNW_X86_EAX: + id = PERF_REG_X86_AX; + break; + case UNW_X86_EDX: + id = PERF_REG_X86_DX; + break; + case UNW_X86_ECX: + id = PERF_REG_X86_CX; + break; + case UNW_X86_EBX: + id = PERF_REG_X86_BX; + break; + case UNW_X86_ESI: + id = PERF_REG_X86_SI; + break; + case UNW_X86_EDI: + id = PERF_REG_X86_DI; + break; + case UNW_X86_EBP: + id = PERF_REG_X86_BP; + break; + case UNW_X86_ESP: + id = PERF_REG_X86_SP; + break; + case UNW_X86_EIP: + id = PERF_REG_X86_IP; + break; + default: + pr_err("unwind: invalid reg id %d\n", regnum); + return -EINVAL; + } + + return id; +} +#endif /* LIBUNWIND_X86_32 */ diff --git a/tools/perf/util/Build b/tools/perf/util/Build index 2e21529..2dd3939 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -1,3 +1,5 @@ +include ../scripts/Makefile.include + libperf-y += alias.o libperf-y += annotate.o libperf-y += build-id.o @@ -99,6 +101,10 @@ libperf-$(CONFIG_DWARF) += dwarf-aux.o libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o libperf-$(CONFIG_LOCAL_LIBUNWIND)+= unwind-libunwind.o libperf-$(CONFIG_LIBUNWIND) += unwind-libunwind_common.o +libperf-$(CONFIG_LIBUNWIND_X86) += unwind-libunwind_x86_32.o + +$(OUTPUT)util/unwind-libunwind_x86_32.o: util/unwind-libunwind.c arch/x86/util/unwind-libunwind.c + $(QUIET_CC)$(CC) $(CFLAGS) -DARCH_UNWIND_LIBUNWIND -Iarch/x86/include/libunwind -c -o $@ util/unwind-libunwind.c libperf-$(CONFIG_LIBBABELTRACE) += data-convert-bt.o diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c index 2a8d24e..1844431 100644 --- a/tools/perf/util/unwind-libunwind.c +++ b/tools/perf/util/unwind-libunwind.c @@ -527,7 +527,7 @@ static int access_reg(unw_addr_space_t __maybe_unused as, return 0; } - id = libunwind__arch_reg_id(regnum); + id = LIBUNWIND__ARCH_REG_ID(regnum); if (id < 0) return -EINVAL; diff --git a/tools/perf/util/unwind-libunwind_common.c b/tools/perf/util/unwind-libunwind_common.c index f67707d..dbc44b1 100644 --- a/tools/perf/util/unwind-libunwind_common.c +++ b/tools/perf/util/unwind-libunwind_common.c @@ -83,10 +83,11 @@ void unwind__get_arch(struct thread *thread, struct map *map) dso_type == DSO__TYPE_64BIT); if (dso_type != DSO__TYPE_64BIT) { #ifdef HAVE_LIBUNWIND_X86_SUPPORT - pr_err("unwind: target platform=%s is not implemented\n", - arch); -#endif + register_unwind_libunwind_ops( +
[PATCH v3 3/7] perf tools: Remove the logical that skip buildid cache if symfs is given
Symfs dir and buildid dir are two places that perf looks into for symbols, currently, if symfs dir is given, buildid-cache is skipped. In the cross-platform perf record/script scenario, we need vdsos in buildid-cache dir and other libs in symfs dir at the same time. And consider that the binaries indexed by buildid do not cause ambiguity, this patch simply removes that logical. Signed-off-by: He Kuang --- tools/perf/util/dso.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c index b39b80c..a07166c5 100644 --- a/tools/perf/util/dso.c +++ b/tools/perf/util/dso.c @@ -64,8 +64,7 @@ int dso__read_binary_type_filename(const struct dso *dso, 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, filename, size) == NULL)) + if (dso__build_id_filename(dso, filename, size) == NULL) ret = -1; break; -- 1.8.5.2
[PATCH v3 7/7] perf callchain: Support aarch64 cross-platform
Support aarch64 cross platform callchain unwind. Signed-off-by: He Kuang --- .../perf/arch/arm64/include/libunwind/libunwind-arch.h | 18 ++ tools/perf/arch/arm64/util/unwind-libunwind.c | 5 - tools/perf/config/Makefile | 12 tools/perf/util/Build | 4 tools/perf/util/unwind-libunwind_common.c | 12 tools/perf/util/unwind.h | 3 +++ 6 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 tools/perf/arch/arm64/include/libunwind/libunwind-arch.h diff --git a/tools/perf/arch/arm64/include/libunwind/libunwind-arch.h b/tools/perf/arch/arm64/include/libunwind/libunwind-arch.h new file mode 100644 index 000..7bc8a00 --- /dev/null +++ b/tools/perf/arch/arm64/include/libunwind/libunwind-arch.h @@ -0,0 +1,18 @@ +#ifndef _LIBUNWIND_ARCH_H +#define _LIBUNWIND_ARCH_H + +#include +#include <../perf_regs.h> +#include <../../../../../../arch/arm64/include/uapi/asm/perf_regs.h> + +#define LIBUNWIND_AARCH64 +int libunwind__aarch64_reg_id(int regnum); + +#include <../../../arm64/util/unwind-libunwind.c> + +#define LIBUNWIND__ARCH_REG_ID libunwind__aarch64_reg_id + +#define UNWT_PREFIXUNW_PASTE(UNW_PASTE(_U, aarch64), _) +#define UNWT_OBJ(fn) UNW_PASTE(UNWT_PREFIX, fn) + +#endif /* _LIBUNWIND_ARCH_H */ diff --git a/tools/perf/arch/arm64/util/unwind-libunwind.c b/tools/perf/arch/arm64/util/unwind-libunwind.c index a87afa9..5b557a5 100644 --- a/tools/perf/arch/arm64/util/unwind-libunwind.c +++ b/tools/perf/arch/arm64/util/unwind-libunwind.c @@ -1,11 +1,14 @@ #include -#include #include "perf_regs.h" #include "../../util/unwind.h" #include "../../util/debug.h" +#ifndef LIBUNWIND_AARCH64 int libunwind__arch_reg_id(int regnum) +#else +int libunwind__aarch64_reg_id(int regnum) +#endif { switch (regnum) { case UNW_AARCH64_X0: diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index 16f14b1..c1bfc5e 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile @@ -353,6 +353,18 @@ ifndef NO_LIBUNWIND have_libunwind = 1 endif + ifeq ($(feature-libunwind-aarch64), 1) +$(call detected,CONFIG_LIBUNWIND_AARCH64) +CFLAGS += -DHAVE_LIBUNWIND_AARCH64_SUPPORT +LDFLAGS += -lunwind -lunwind-aarch64 +have_libunwind = 1 +$(call feature_check,libunwind-debug-frame-aarch64) +ifneq ($(feature-libunwind-debug-frame-aarch64), 1) + msg := $(warning No debug_frame support found in libunwind-aarch64); + CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME_AARCH64 +endif + endif + ifneq ($(feature-libunwind), 1) msg := $(warning No libunwind found. Please install libunwind-dev[el] >= 1.1 and/or set LIBUNWIND_DIR); NO_LOCAL_LIBUNWIND := 1 diff --git a/tools/perf/util/Build b/tools/perf/util/Build index 2dd3939..10e42ad 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -102,10 +102,14 @@ libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o libperf-$(CONFIG_LOCAL_LIBUNWIND)+= unwind-libunwind.o libperf-$(CONFIG_LIBUNWIND) += unwind-libunwind_common.o libperf-$(CONFIG_LIBUNWIND_X86) += unwind-libunwind_x86_32.o +libperf-$(CONFIG_LIBUNWIND_AARCH64) += unwind-libunwind_arm64.o $(OUTPUT)util/unwind-libunwind_x86_32.o: util/unwind-libunwind.c arch/x86/util/unwind-libunwind.c $(QUIET_CC)$(CC) $(CFLAGS) -DARCH_UNWIND_LIBUNWIND -Iarch/x86/include/libunwind -c -o $@ util/unwind-libunwind.c +$(OUTPUT)util/unwind-libunwind_arm64.o: util/unwind-libunwind.c arch/arm64/util/unwind-libunwind.c + $(QUIET_CC)$(CC) $(CFLAGS) -DARCH_UNWIND_LIBUNWIND -Iarch/arm64/include/libunwind -c -o $@ util/unwind-libunwind.c + libperf-$(CONFIG_LIBBABELTRACE) += data-convert-bt.o libperf-y += scripting-engines/ diff --git a/tools/perf/util/unwind-libunwind_common.c b/tools/perf/util/unwind-libunwind_common.c index dbc44b1..14a209d 100644 --- a/tools/perf/util/unwind-libunwind_common.c +++ b/tools/perf/util/unwind-libunwind_common.c @@ -90,6 +90,18 @@ void unwind__get_arch(struct thread *thread, struct map *map) #endif } else use_local_unwind = 1; + } else if (!strcmp(arch, "aarch64") || !strncmp(arch, "arm", 3)) { + pr_debug("Thread map is ARM, 64bit is %d, dso=%s\n", +dso_type == DSO__TYPE_64BIT, map->dso->name); + if (dso_type == DSO__TYPE_64BIT) { +#ifdef HAVE_LIBUNWIND_AARCH64_SUPPORT + register_unwind_libunwind_ops( + &_Uaarch64_unwind_libunwind_ops, thread); +#else + register_null_unwind_libunwind_ops(thread); +#endif + } else + use_local_unwind = 1; } else { use_local_unwind = 1; } diff --git
[PATCH v3 2/7] perf tools: Store vdso buildid unconditionally
When unwinding callchains on a different machine, vdso info should be provided so the unwind process won't be interrupted if address falls into vdso region. But in most cases, the addresses of sample events are not in vdso range, the buildid of a zero hit vdso won't be stored into perf.data. This patch stores vdso buildid regardless of whether the vdso is hit or not. Signed-off-by: He Kuang --- tools/perf/util/build-id.c | 2 +- tools/perf/util/dso.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c index 0573c2e..bdc7580 100644 --- a/tools/perf/util/build-id.c +++ b/tools/perf/util/build-id.c @@ -256,7 +256,7 @@ static int machine__write_buildid_table(struct machine *machine, int fd) size_t name_len; bool in_kernel = false; - if (!pos->hit) + if (!pos->hit && !dso__is_vdso(pos)) continue; if (dso__is_vdso(pos)) { diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c index 8e639543..b39b80c 100644 --- a/tools/perf/util/dso.c +++ b/tools/perf/util/dso.c @@ -7,6 +7,7 @@ #include "auxtrace.h" #include "util.h" #include "debug.h" +#include "vdso.h" char dso__symtab_origin(const struct dso *dso) { @@ -1169,7 +1170,7 @@ bool __dsos__read_build_ids(struct list_head *head, bool with_hits) struct dso *pos; list_for_each_entry(pos, head, node) { - if (with_hits && !pos->hit) + if (with_hits && !pos->hit && !dso__is_vdso(pos)) continue; if (pos->has_build_id) { have_build_id = true; -- 1.8.5.2
[PATCH v3 0/7] Add support for remote unwind
v2 url: http://thread.gmane.org/gmane.linux.kernel/2218373 Currently, perf script uses host unwind methods(local unwind) to parse perf.data callchain info regardless of the target architecture. So we get wrong result and no promotion when do remote unwind on other platforms/machines. This patchset adds build tests for the supported platforms for remote unwinding, and checks whether a dso is 32-bit or 64-bit according to elf class info for each thread to let perf use the correct remote unwind methods instead. Only x86 and aarch64 is added in this patchset to show the work flow, other platforms can be added easily. We can see the right result for unwind info on different machines, for example: perf.data recorded on i686 qemu with '-g' option and parsed on x86_64 machine. before this patchset: hello 1219 [001] 72190.667975: probe:sys_close: (c1169d60) c1169d61 sys_close ([kernel.kallsyms]) c189c0d7 sysenter_past_esp ([kernel.kallsyms]) b777aba9 [unknown] ([vdso32]) after: (Add vdso into buildid-cache first by 'perf buildid-cache -a' and libraries are provided in symfs dir) hello 1219 [001] 72190.667975: probe:sys_close: (c1169d60) c1169d61 sys_close ([kernel.kallsyms]) c189c0d7 sysenter_past_esp ([kernel.kallsyms]) b777aba9 __kernel_vsyscall ([vdso32]) b76971cc close (/lib/libc-2.22.so) 804842e fib (/tmp/hello) 804849d main (/tmp/hello) b75d746e __libc_start_main (/lib/libc-2.22.so) 8048341 _start (/tmp/hello) v3: - Remove --vdso option, store vdso buildid in perf.data and let perf fetch it automatically. - Use existing dso__type() function to test if dso is 32-bit or 64-bit. v2: - Explain the reason why we can omit dwarf judgement when recording in commit message. - Elaborate on why we need to add a custom vdso path option, and change the type name to DSO_BINARY_TYPE__VDSO. - Hide the build tests status for cross platform unwind. - Keep generic version of libunwind-debug-frame test. - Put 32/64-bit test functions into separate patch. - Extract unwind related functions to unwind-libunwind.c and add new file for common parts used by both local and remote unwind. - Eliminate most of the ifdefs in .c file. Thanks. He Kuang (7): perf tools: Set vdso name to vdso[64,32] depending on platform perf tools: Store vdso buildid unconditionally perf tools: Remove the logical that skip buildid cache if symfs is given perf tools: Promote proper messages for cross-platform unwind perf callchain: Add support for cross-platform unwind perf callchain: Support x86 target platform perf callchain: Support aarch64 cross-platform .../arch/arm64/include/libunwind/libunwind-arch.h | 18 tools/perf/arch/arm64/util/unwind-libunwind.c | 5 +- .../arch/x86/include/libunwind/libunwind-arch.h| 18 tools/perf/arch/x86/util/unwind-libunwind.c| 42 tools/perf/config/Makefile | 35 ++- tools/perf/util/Build | 13 ++- tools/perf/util/build-id.c | 2 +- tools/perf/util/dso.c | 6 +- tools/perf/util/thread.c | 7 +- tools/perf/util/thread.h | 14 ++- tools/perf/util/unwind-libunwind.c | 49 +++-- tools/perf/util/unwind-libunwind_common.c | 114 + tools/perf/util/unwind.h | 48 +++-- tools/perf/util/vdso.h | 7 +- 14 files changed, 348 insertions(+), 30 deletions(-) create mode 100644 tools/perf/arch/arm64/include/libunwind/libunwind-arch.h create mode 100644 tools/perf/arch/x86/include/libunwind/libunwind-arch.h create mode 100644 tools/perf/util/unwind-libunwind_common.c -- 1.8.5.2
[PATCH v3 5/7] perf callchain: Add support for cross-platform unwind
Use thread specific unwind ops to unwind cross-platform callchains. Before this patch, unwind methods is suitable for local unwind, this patch changes the fixed methods to thread/map related. Each time a map is inserted, we find the target arch and see if this platform can be remote unwind. In this patch, we test for x86 platform and only show proper messages. The real unwind methods are not implemented, will be introduced in next patch. Common function used by both local unwind and remote unwind are separated into new file 'unwind-libunwind_common.c'. Signed-off-by: He Kuang --- tools/perf/config/Makefile| 19 +- tools/perf/util/Build | 3 +- tools/perf/util/thread.c | 5 +- tools/perf/util/thread.h | 14 - tools/perf/util/unwind-libunwind.c| 74 +++--- tools/perf/util/unwind-libunwind_common.c | 101 ++ tools/perf/util/unwind.h | 35 --- 7 files changed, 197 insertions(+), 54 deletions(-) create mode 100644 tools/perf/util/unwind-libunwind_common.c diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index a86b864..16f14b1 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile @@ -345,14 +345,24 @@ ifeq ($(ARCH),powerpc) endif ifndef NO_LIBUNWIND + have_libunwind = ifeq ($(feature-libunwind-x86), 1) -LIBUNWIND_LIBS += -lunwind-x86 $(call detected,CONFIG_LIBUNWIND_X86) CFLAGS += -DHAVE_LIBUNWIND_X86_SUPPORT +LDFLAGS += -lunwind -lunwind-x86 +have_libunwind = 1 endif ifneq ($(feature-libunwind), 1) msg := $(warning No libunwind found. Please install libunwind-dev[el] >= 1.1 and/or set LIBUNWIND_DIR); +NO_LOCAL_LIBUNWIND := 1 + else +have_libunwind = 1 +CFLAGS += -DHAVE_LIBUNWIND_LOCAL_SUPPORT +$(call detected,CONFIG_LOCAL_LIBUNWIND) + endif + + ifneq ($(have_libunwind), 1) NO_LIBUNWIND := 1 endif endif @@ -392,7 +402,7 @@ else NO_DWARF_UNWIND := 1 endif -ifndef NO_LIBUNWIND +ifndef NO_LOCAL_LIBUNWIND ifeq ($(ARCH),$(filter $(ARCH),arm arm64)) $(call feature_check,libunwind-debug-frame) ifneq ($(feature-libunwind-debug-frame), 1) @@ -403,12 +413,15 @@ ifndef NO_LIBUNWIND # non-ARM has no dwarf_find_debug_frame() function: CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME endif - CFLAGS += -DHAVE_LIBUNWIND_SUPPORT EXTLIBS += $(LIBUNWIND_LIBS) CFLAGS += $(LIBUNWIND_CFLAGS) LDFLAGS += $(LIBUNWIND_LDFLAGS) endif +ifndef NO_LIBUNWIND + CFLAGS += -DHAVE_LIBUNWIND_SUPPORT +endif + ifndef NO_LIBAUDIT ifneq ($(feature-libaudit), 1) msg := $(warning No libaudit.h found, disables 'trace' tool, please install audit-libs-devel or libaudit-dev); diff --git a/tools/perf/util/Build b/tools/perf/util/Build index ea4ac03..2e21529 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -97,7 +97,8 @@ libperf-$(CONFIG_DWARF) += probe-finder.o libperf-$(CONFIG_DWARF) += dwarf-aux.o libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o -libperf-$(CONFIG_LIBUNWIND) += unwind-libunwind.o +libperf-$(CONFIG_LOCAL_LIBUNWIND)+= unwind-libunwind.o +libperf-$(CONFIG_LIBUNWIND) += unwind-libunwind_common.o libperf-$(CONFIG_LIBBABELTRACE) += data-convert-bt.o diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 244c4f6..2274263 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c @@ -41,9 +41,6 @@ struct thread *thread__new(pid_t pid, pid_t tid) thread->cpu = -1; INIT_LIST_HEAD(&thread->comm_list); - if (unwind__prepare_access(thread) < 0) - goto err_thread; - comm_str = malloc(32); if (!comm_str) goto err_thread; @@ -57,6 +54,8 @@ struct thread *thread__new(pid_t pid, pid_t tid) list_add(&comm->list, &thread->comm_list); atomic_set(&thread->refcnt, 1); RB_CLEAR_NODE(&thread->rb_node); + + register_null_unwind_libunwind_ops(thread); } return thread; diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h index e214207..6f2d4cd 100644 --- a/tools/perf/util/thread.h +++ b/tools/perf/util/thread.h @@ -15,6 +15,17 @@ struct thread_stack; +struct unwind_entry; +typedef int (*unwind_entry_cb_t)(struct unwind_entry *entry, void *arg); +struct unwind_libunwind_ops { + int (*prepare_access)(struct thread *thread); + void (*flush_access)(struct thread *thread); + void (*finish_access)(struct thread *thread); + int (*get_entries)(unwind_entry_cb_t cb, void *arg, + struct thread *thread, + struct perf_sample *data, int max_stack); +}; + struct thread { union { struct r
[PATCH v3 4/7] perf tools: Promote proper messages for cross-platform unwind
Currently, perf script uses host unwind methods to parse perf.data callchain info regardless of the target architecture. So we get wrong result and no promotion when unwinding callchains of x86(32-bit) on x86(64-bit) machine. This patch shows proper error messages when we do remote unwind x86(32-bit) on other machines. Same thing for other platforms will be added in next patches. Signed-off-by: He Kuang --- tools/perf/config/Makefile | 6 ++ tools/perf/util/thread.c | 2 ++ tools/perf/util/unwind-libunwind.c | 33 + tools/perf/util/unwind.h | 5 + 4 files changed, 46 insertions(+) diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index 1e46277..a86b864 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile @@ -345,6 +345,12 @@ ifeq ($(ARCH),powerpc) endif ifndef NO_LIBUNWIND + ifeq ($(feature-libunwind-x86), 1) +LIBUNWIND_LIBS += -lunwind-x86 +$(call detected,CONFIG_LIBUNWIND_X86) +CFLAGS += -DHAVE_LIBUNWIND_X86_SUPPORT + endif + ifneq ($(feature-libunwind), 1) msg := $(warning No libunwind found. Please install libunwind-dev[el] >= 1.1 and/or set LIBUNWIND_DIR); NO_LIBUNWIND := 1 diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index dfd00c6..244c4f6 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c @@ -186,6 +186,8 @@ void thread__insert_map(struct thread *thread, struct map *map) { map_groups__fixup_overlappings(thread->mg, map, stderr); map_groups__insert(thread->mg, map); + + unwind__get_arch(thread, map); } static int thread__clone_map_groups(struct thread *thread, diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c index 63687d3..d464c35 100644 --- a/tools/perf/util/unwind-libunwind.c +++ b/tools/perf/util/unwind-libunwind.c @@ -680,3 +680,36 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg, return get_entries(&ui, cb, arg, max_stack); } + +void unwind__get_arch(struct thread *thread, struct map *map) +{ + char *arch; + enum dso_type dso_type; + + if (!thread->mg->machine->env) + return; + + dso_type = dso__type(map->dso, thread->mg->machine); + if (dso_type == DSO__TYPE_UNKNOWN) + return; + + if (thread->addr_space) + pr_debug("Thread map already set, 64bit is %d, dso=%s\n", +dso_type == DSO__TYPE_64BIT, map->dso->name); + + arch = thread->mg->machine->env->arch; + + if (!strcmp(arch, "x86_64") + || !strcmp(arch, "x86") + || !strcmp(arch, "i686")) { + pr_debug("Thread map is X86, 64bit is %d\n", +dso_type == DSO__TYPE_64BIT); + if (dso_type != DSO__TYPE_64BIT) +#ifdef HAVE_LIBUNWIND_X86_SUPPORT + pr_err("target platform=%s is not implemented!\n", + arch); +#else + pr_err("target platform=%s is not supported!\n", arch); +#endif + } +} diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h index 12790cf..889d630 100644 --- a/tools/perf/util/unwind.h +++ b/tools/perf/util/unwind.h @@ -24,6 +24,7 @@ int libunwind__arch_reg_id(int regnum); int unwind__prepare_access(struct thread *thread); void unwind__flush_access(struct thread *thread); void unwind__finish_access(struct thread *thread); +void unwind__get_arch(struct thread *thread, struct map *map); #else static inline int unwind__prepare_access(struct thread *thread __maybe_unused) { @@ -32,6 +33,8 @@ static inline int unwind__prepare_access(struct thread *thread __maybe_unused) static inline void unwind__flush_access(struct thread *thread __maybe_unused) {} static inline void unwind__finish_access(struct thread *thread __maybe_unused) {} +static inline void unwind__get_arch(struct thread *thread __maybe_unused, + struct map *map __maybe_unused) {} #endif #else static inline int @@ -51,5 +54,7 @@ static inline int unwind__prepare_access(struct thread *thread __maybe_unused) static inline void unwind__flush_access(struct thread *thread __maybe_unused) {} static inline void unwind__finish_access(struct thread *thread __maybe_unused) {} +static inline void unwind__get_arch(struct thread *thread __maybe_unused, + struct map *map __maybe_unused) {} #endif /* HAVE_DWARF_UNWIND_SUPPORT */ #endif /* __UNWIND_H */ -- 1.8.5.2
[PATCH v5 3/5] perf callchain: Add support for cross-platform unwind
Use thread specific unwind ops to unwind cross-platform callchains. Currently, unwind methods is suitable for local unwind, this patch changes the fixed methods to thread/map related. Each time a map is inserted, we find the target arch and see if this platform can be remote unwind. We test for x86 platform and only show proper messages. The real unwind methods are not implemented, will be introduced in next patch. CONFIG_LIBUNWIND/NO_LIBUNWIND are changed to CONFIG_LOCAL_LIBUNWIND/NO_LOCAL_LIBUNWIND for retaining local unwind features. CONFIG_LIBUNWIND stands for either local or remote or both unwind are supported and NO_LIBUNWIND means neither local nor remote libunwind are supported. Signed-off-by: He Kuang --- tools/perf/arch/x86/util/Build| 2 +- tools/perf/config/Makefile| 23 +- tools/perf/util/Build | 2 +- tools/perf/util/thread.c | 5 +-- tools/perf/util/thread.h | 17 ++-- tools/perf/util/unwind-libunwind.c| 49 + tools/perf/util/unwind-libunwind_common.c | 71 +-- tools/perf/util/unwind.h | 37 +++- 8 files changed, 173 insertions(+), 33 deletions(-) diff --git a/tools/perf/arch/x86/util/Build b/tools/perf/arch/x86/util/Build index 4659703..bc24b75 100644 --- a/tools/perf/arch/x86/util/Build +++ b/tools/perf/arch/x86/util/Build @@ -7,7 +7,7 @@ libperf-y += perf_regs.o libperf-$(CONFIG_DWARF) += dwarf-regs.o libperf-$(CONFIG_BPF_PROLOGUE) += dwarf-regs.o -libperf-$(CONFIG_LIBUNWIND) += unwind-libunwind.o +libperf-$(CONFIG_LOCAL_LIBUNWIND)+= unwind-libunwind.o libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o libperf-$(CONFIG_AUXTRACE) += auxtrace.o diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index c9e1625..8ac0440 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile @@ -354,15 +354,31 @@ ifeq ($(ARCH),powerpc) endif ifndef NO_LIBUNWIND + have_libunwind = ifeq ($(feature-libunwind-x86), 1) $(call detected,CONFIG_LIBUNWIND_X86) CFLAGS += -DHAVE_LIBUNWIND_X86_SUPPORT +LDFLAGS += -lunwind-x86 +have_libunwind = 1 endif ifneq ($(feature-libunwind), 1) msg := $(warning No libunwind found. Please install libunwind-dev[el] >= 1.1 and/or set LIBUNWIND_DIR); +NO_LOCAL_LIBUNWIND := 1 + else +have_libunwind = 1 +CFLAGS += -DHAVE_LIBUNWIND_LOCAL_SUPPORT +$(call detected,CONFIG_LOCAL_LIBUNWIND) + endif + + ifneq ($(have_libunwind), 1) NO_LIBUNWIND := 1 + else +CFLAGS += -I$(LIBUNWIND_DIR)/include +LDFLAGS += -L$(LIBUNWIND_DIR)/lib endif +else + NO_LOCAL_LIBUNWIND := 1 endif ifndef NO_LIBBPF @@ -400,7 +416,7 @@ else NO_DWARF_UNWIND := 1 endif -ifndef NO_LIBUNWIND +ifndef NO_LOCAL_LIBUNWIND ifeq ($(ARCH),$(filter $(ARCH),arm arm64)) $(call feature_check,libunwind-debug-frame) ifneq ($(feature-libunwind-debug-frame), 1) @@ -411,12 +427,15 @@ ifndef NO_LIBUNWIND # non-ARM has no dwarf_find_debug_frame() function: CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME endif - CFLAGS += -DHAVE_LIBUNWIND_SUPPORT EXTLIBS += $(LIBUNWIND_LIBS) CFLAGS += $(LIBUNWIND_CFLAGS) LDFLAGS += $(LIBUNWIND_LDFLAGS) endif +ifndef NO_LIBUNWIND + CFLAGS += -DHAVE_LIBUNWIND_SUPPORT +endif + ifndef NO_LIBAUDIT ifneq ($(feature-libaudit), 1) msg := $(warning No libaudit.h found, disables 'trace' tool, please install audit-libs-devel or libaudit-dev); diff --git a/tools/perf/util/Build b/tools/perf/util/Build index 25c31fb..ce69721 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -99,7 +99,7 @@ libperf-$(CONFIG_DWARF) += probe-finder.o libperf-$(CONFIG_DWARF) += dwarf-aux.o libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o -libperf-$(CONFIG_LIBUNWIND) += unwind-libunwind.o +libperf-$(CONFIG_LOCAL_LIBUNWIND)+= unwind-libunwind.o libperf-$(CONFIG_LIBUNWIND) += unwind-libunwind_common.o libperf-$(CONFIG_LIBBABELTRACE) += data-convert-bt.o diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 3043113..4e1aaf5 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c @@ -43,9 +43,6 @@ struct thread *thread__new(pid_t pid, pid_t tid) thread->cpu = -1; INIT_LIST_HEAD(&thread->comm_list); - if (unwind__prepare_access(thread) < 0) - goto err_thread; - comm_str = malloc(32); if (!comm_str) goto err_thread; @@ -59,6 +56,8 @@ struct thread *thread__new(pid_t pid, pid_t tid) list_add(&comm->list, &thread->comm_list); atomic_set(&thread->refcnt, 1); RB_CLEAR_NODE(&thread->rb_node); + + register_null_unwind_libunwind_ops(thread); } return thre
[PATCH v5 5/5] perf callchain: Support aarch64 cross-platform
Support aarch64 cross platform callchain unwind. Signed-off-by: He Kuang --- .../perf/arch/arm64/include/libunwind/libunwind-arch.h | 18 ++ tools/perf/arch/arm64/util/unwind-libunwind.c | 5 - tools/perf/config/Makefile | 12 tools/perf/util/Build | 4 tools/perf/util/unwind-libunwind_common.c | 10 ++ tools/perf/util/unwind.h | 3 +++ 6 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 tools/perf/arch/arm64/include/libunwind/libunwind-arch.h diff --git a/tools/perf/arch/arm64/include/libunwind/libunwind-arch.h b/tools/perf/arch/arm64/include/libunwind/libunwind-arch.h new file mode 100644 index 000..47d13a6 --- /dev/null +++ b/tools/perf/arch/arm64/include/libunwind/libunwind-arch.h @@ -0,0 +1,18 @@ +#ifndef _LIBUNWIND_ARCH_H +#define _LIBUNWIND_ARCH_H + +#include +#include <../perf_regs.h> +#include <../../../../../../arch/arm64/include/uapi/asm/perf_regs.h> + +#define LIBUNWIND_AARCH64 +int libunwind__aarch64_reg_id(int regnum); + +#define LIBUNWIND__ARCH_REG_ID libunwind__aarch64_reg_id + +#include <../../../arm64/util/unwind-libunwind.c> + +#define UNWT_PREFIXUNW_PASTE(UNW_PASTE(_U, aarch64), _) +#define UNWT_OBJ(fn) UNW_PASTE(UNWT_PREFIX, fn) + +#endif /* _LIBUNWIND_ARCH_H */ diff --git a/tools/perf/arch/arm64/util/unwind-libunwind.c b/tools/perf/arch/arm64/util/unwind-libunwind.c index a87afa9..5b557a5 100644 --- a/tools/perf/arch/arm64/util/unwind-libunwind.c +++ b/tools/perf/arch/arm64/util/unwind-libunwind.c @@ -1,11 +1,14 @@ #include -#include #include "perf_regs.h" #include "../../util/unwind.h" #include "../../util/debug.h" +#ifndef LIBUNWIND_AARCH64 int libunwind__arch_reg_id(int regnum) +#else +int libunwind__aarch64_reg_id(int regnum) +#endif { switch (regnum) { case UNW_AARCH64_X0: diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index 8ac0440..eb7cbce 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile @@ -362,6 +362,18 @@ ifndef NO_LIBUNWIND have_libunwind = 1 endif + ifeq ($(feature-libunwind-aarch64), 1) +$(call detected,CONFIG_LIBUNWIND_AARCH64) +CFLAGS += -DHAVE_LIBUNWIND_AARCH64_SUPPORT +LDFLAGS += -lunwind-aarch64 +have_libunwind = 1 +$(call feature_check,libunwind-debug-frame-aarch64) +ifneq ($(feature-libunwind-debug-frame-aarch64), 1) + msg := $(warning No debug_frame support found in libunwind-aarch64); + CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME_AARCH64 +endif + endif + ifneq ($(feature-libunwind), 1) msg := $(warning No libunwind found. Please install libunwind-dev[el] >= 1.1 and/or set LIBUNWIND_DIR); NO_LOCAL_LIBUNWIND := 1 diff --git a/tools/perf/util/Build b/tools/perf/util/Build index 2373130..f1b51a2 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -104,10 +104,14 @@ libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o libperf-$(CONFIG_LOCAL_LIBUNWIND)+= unwind-libunwind.o libperf-$(CONFIG_LIBUNWIND) += unwind-libunwind_common.o libperf-$(CONFIG_LIBUNWIND_X86) += unwind-libunwind_x86_32.o +libperf-$(CONFIG_LIBUNWIND_AARCH64) += unwind-libunwind_arm64.o $(OUTPUT)util/unwind-libunwind_x86_32.o: util/unwind-libunwind.c arch/x86/util/unwind-libunwind.c $(QUIET_CC)$(CC) $(CFLAGS) -DREMOTE_UNWIND_LIBUNWIND -Iarch/x86/include/libunwind -c -o $@ util/unwind-libunwind.c +$(OUTPUT)util/unwind-libunwind_arm64.o: util/unwind-libunwind.c arch/arm64/util/unwind-libunwind.c + $(QUIET_CC)$(CC) $(CFLAGS) -DREMOTE_UNWIND_LIBUNWIND -Iarch/arm64/include/libunwind -c -o $@ util/unwind-libunwind.c + libperf-$(CONFIG_LIBBABELTRACE) += data-convert-bt.o libperf-y += scripting-engines/ diff --git a/tools/perf/util/unwind-libunwind_common.c b/tools/perf/util/unwind-libunwind_common.c index 619c6c0..d19b062 100644 --- a/tools/perf/util/unwind-libunwind_common.c +++ b/tools/perf/util/unwind-libunwind_common.c @@ -89,6 +89,16 @@ void unwind__get_arch(struct thread *thread, struct map *map) #endif use_local_unwind = 0; } + } else if (!strcmp(arch, "arm64") || !strcmp(arch, "arm")) { + if (dso_type == DSO__TYPE_64BIT) { +#ifdef HAVE_LIBUNWIND_AARCH64_SUPPORT + register_unwind_libunwind_ops( + &_Uaarch64_unwind_libunwind_ops, thread); +#else + register_null_unwind_libunwind_ops(thread); +#endif + use_local_unwind = 0; + } } if (use_local_unwind) diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h index 7dafb6e..359f756 100644 --- a/tools/perf/util/unwind.h +++ b/tools/perf/util/unwind.h @@ -60,6 +60,9 @@ register_null_unwind_libunwind_ops(s
[PATCH v5 4/5] perf callchain: Support x86 target platform
Support x86(32-bit) cross platform callchain unwind. Signed-off-by: He Kuang --- .../perf/arch/x86/include/libunwind/libunwind-arch.h | 18 ++ tools/perf/arch/x86/util/unwind-libunwind.c | 19 ++- tools/perf/util/Build | 6 ++ tools/perf/util/unwind-libunwind_common.c | 6 -- tools/perf/util/unwind.h | 5 + 5 files changed, 47 insertions(+), 7 deletions(-) create mode 100644 tools/perf/arch/x86/include/libunwind/libunwind-arch.h diff --git a/tools/perf/arch/x86/include/libunwind/libunwind-arch.h b/tools/perf/arch/x86/include/libunwind/libunwind-arch.h new file mode 100644 index 000..be8c675 --- /dev/null +++ b/tools/perf/arch/x86/include/libunwind/libunwind-arch.h @@ -0,0 +1,18 @@ +#ifndef _LIBUNWIND_ARCH_H +#define _LIBUNWIND_ARCH_H + +#include +#include <../perf_regs.h> +#include <../../../../../../arch/x86/include/uapi/asm/perf_regs.h> + +#define LIBUNWIND_X86_32 +int libunwind__x86_reg_id(int regnum); + +#define LIBUNWIND__ARCH_REG_ID libunwind__x86_reg_id + +#include <../../../x86/util/unwind-libunwind.c> + +#define UNWT_PREFIXUNW_PASTE(UNW_PASTE(_U, x86), _) +#define UNWT_OBJ(fn) UNW_PASTE(UNWT_PREFIX, fn) + +#endif /* _LIBUNWIND_ARCH_H */ diff --git a/tools/perf/arch/x86/util/unwind-libunwind.c b/tools/perf/arch/x86/util/unwind-libunwind.c index db25e93..28831d8 100644 --- a/tools/perf/arch/x86/util/unwind-libunwind.c +++ b/tools/perf/arch/x86/util/unwind-libunwind.c @@ -1,12 +1,18 @@ #include +#if defined(LIBUNWIND_X86_32) +#include +#elif defined(LIBUNWIND_X86_64) +#include +#elif defined(HAVE_LIBUNWIND_LOCAL_SUPPORT) #include +#endif #include "perf_regs.h" #include "../../util/unwind.h" #include "../../util/debug.h" -#ifdef HAVE_ARCH_X86_64_SUPPORT -int libunwind__arch_reg_id(int regnum) +#if !defined(REMOTE_UNWIND_LIBUNWIND) && defined(HAVE_ARCH_X86_64_SUPPORT) +int LIBUNWIND__ARCH_REG_ID(int regnum) { int id; @@ -69,8 +75,11 @@ int libunwind__arch_reg_id(int regnum) return id; } -#else -int libunwind__arch_reg_id(int regnum) +#endif + +#if !defined(REMOTE_UNWIND_LIBUNWIND) && !defined(HAVE_ARCH_X86_64_SUPPORT) || \ + defined(LIBUNWIND_X86_32) +int LIBUNWIND__ARCH_REG_ID(int regnum) { int id; @@ -109,4 +118,4 @@ int libunwind__arch_reg_id(int regnum) return id; } -#endif /* HAVE_ARCH_X86_64_SUPPORT */ +#endif diff --git a/tools/perf/util/Build b/tools/perf/util/Build index ce69721..2373130 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -1,3 +1,5 @@ +include ../scripts/Makefile.include + libperf-y += alias.o libperf-y += annotate.o libperf-y += build-id.o @@ -101,6 +103,10 @@ libperf-$(CONFIG_DWARF) += dwarf-aux.o libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o libperf-$(CONFIG_LOCAL_LIBUNWIND)+= unwind-libunwind.o libperf-$(CONFIG_LIBUNWIND) += unwind-libunwind_common.o +libperf-$(CONFIG_LIBUNWIND_X86) += unwind-libunwind_x86_32.o + +$(OUTPUT)util/unwind-libunwind_x86_32.o: util/unwind-libunwind.c arch/x86/util/unwind-libunwind.c + $(QUIET_CC)$(CC) $(CFLAGS) -DREMOTE_UNWIND_LIBUNWIND -Iarch/x86/include/libunwind -c -o $@ util/unwind-libunwind.c libperf-$(CONFIG_LIBBABELTRACE) += data-convert-bt.o diff --git a/tools/perf/util/unwind-libunwind_common.c b/tools/perf/util/unwind-libunwind_common.c index f44833b..619c6c0 100644 --- a/tools/perf/util/unwind-libunwind_common.c +++ b/tools/perf/util/unwind-libunwind_common.c @@ -82,9 +82,11 @@ void unwind__get_arch(struct thread *thread, struct map *map) if (!strcmp(arch, "x86")) { if (dso_type != DSO__TYPE_64BIT) { #ifdef HAVE_LIBUNWIND_X86_SUPPORT - pr_err("unwind: target platform=%s is not implemented\n", arch); -#endif + register_unwind_libunwind_ops( + &_Ux86_unwind_libunwind_ops, thread); +#else register_null_unwind_libunwind_ops(thread); +#endif use_local_unwind = 0; } } diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h index e170be7..7dafb6e 100644 --- a/tools/perf/util/unwind.h +++ b/tools/perf/util/unwind.h @@ -56,6 +56,11 @@ static inline void unwind__get_arch(struct thread *thread __maybe_unused, static inline void register_null_unwind_libunwind_ops(struct thread *thread __maybe_unused) {} #endif + +#ifdef HAVE_LIBUNWIND_X86_SUPPORT +extern struct unwind_libunwind_ops _Ux86_unwind_libunwind_ops; +#endif + #else static inline int unwind__get_entries(unwind_entry_cb_t cb __maybe_unused, -- 1.8.5.2
[PATCH v5 0/5] Add support for remote unwind
v4 url: http://thread.gmane.org/gmane.linux.kernel/2224430 Currently, perf script uses host unwind methods(local unwind) to parse perf.data callchain info regardless of the target architecture. So we get wrong result and no promotion when do remote unwind on other platforms/machines. This patchset checks whether a dso is 32-bit or 64-bit according to elf class info for each thread to let perf use the correct remote unwind methods instead. Only x86 and aarch64 is added in this patchset to show the work flow, other platforms can be added easily. We can see the right result for unwind info on different machines, for example: perf.data recorded on i686 qemu with '-g' option and parsed on x86_64 machine. before this patchset: hello 1219 [001] 72190.667975: probe:sys_close: (c1169d60) c1169d61 sys_close ([kernel.kallsyms]) c189c0d7 sysenter_past_esp ([kernel.kallsyms]) b777aba9 [unknown] ([vdso32]) after: (Add vdso into buildid-cache first by 'perf buildid-cache -a' and libraries are provided in symfs dir) hello 1219 [001] 72190.667975: probe:sys_close: (c1169d60) c1169d61 sys_close ([kernel.kallsyms]) c189c0d7 sysenter_past_esp ([kernel.kallsyms]) b777aba9 __kernel_vsyscall ([vdso32]) b76971cc close (/lib/libc-2.22.so) 804842e fib (/tmp/hello) 804849d main (/tmp/hello) b75d746e __libc_start_main (/lib/libc-2.22.so) 8048341 _start (/tmp/hello) For using remote libunwind libraries, reference this: http://thread.gmane.org/gmane.linux.kernel/2224430 and now we can use LIBUNWIND_DIR to specific custom dirctories containing libunwind libs. v5: - Support LIBUNWIND_DIR args for detect remote libunwind libraries. - Change patch 2/5 commit messages for better understanding. - Self test for local (un)supported, remote un(supported) cases and fix some bugs in v4. v4: - Move reference of buildid dir to 'symfs/.debug' if --symfs is given. - Split makefile changes out from patch 'Add support for cross-platform unwind'. - Use existing code normalize_arch() for testing the arch of perf.data. v3: - Remove --vdso option, store vdso buildid in perf.data and let perf fetch it automatically. - Use existing dso__type() function to test if dso is 32-bit or 64-bit. v2: - Explain the reason why we can omit dwarf judgement when recording in commit message. - Elaborate on why we need to add a custom vdso path option, and change the type name to DSO_BINARY_TYPE__VDSO. - Hide the build tests status for cross platform unwind. - Keep generic version of libunwind-debug-frame test. - Put 32/64-bit test functions into separate patch. - Extract unwind related functions to unwind-libunwind.c and add new file for common parts used by both local and remote unwind. - Eliminate most of the ifdefs in .c file. Thanks. He Kuang (5): perf tools: Use LIBUNWIND_DIR for remote libunwind feature check perf tools: Show warnings for unsupported cross-platform unwind perf callchain: Add support for cross-platform unwind perf callchain: Support x86 target platform perf callchain: Support aarch64 cross-platform .../arch/arm64/include/libunwind/libunwind-arch.h | 18 tools/perf/arch/arm64/util/unwind-libunwind.c | 5 +- tools/perf/arch/common.c | 2 +- tools/perf/arch/common.h | 1 + .../arch/x86/include/libunwind/libunwind-arch.h| 18 tools/perf/arch/x86/util/Build | 2 +- tools/perf/arch/x86/util/unwind-libunwind.c| 19 +++- tools/perf/config/Makefile | 49 - tools/perf/util/Build | 13 ++- tools/perf/util/thread.c | 7 +- tools/perf/util/thread.h | 17 +++- tools/perf/util/unwind-libunwind.c | 49 +++-- tools/perf/util/unwind-libunwind_common.c | 109 + tools/perf/util/unwind.h | 50 -- 14 files changed, 323 insertions(+), 36 deletions(-) create mode 100644 tools/perf/arch/arm64/include/libunwind/libunwind-arch.h create mode 100644 tools/perf/arch/x86/include/libunwind/libunwind-arch.h create mode 100644 tools/perf/util/unwind-libunwind_common.c -- 1.8.5.2
[PATCH v5 1/5] perf tools: Use LIBUNWIND_DIR for remote libunwind feature check
Pass LIBUNWIND_DIR to feature check flags for remote libunwind tests. So perf can be able to detect remote libunwind libraries from arbitrary directory. Signed-off-by: He Kuang --- tools/perf/config/Makefile | 9 + 1 file changed, 9 insertions(+) diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index 1e46277..6f9f566 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile @@ -67,9 +67,18 @@ endif # # make DEBUG=1 LIBUNWIND_DIR=/opt/libunwind/ # + +libunwind_arch_set_flags = $(eval $(libunwind_arch_set_flags_code)) +define libunwind_arch_set_flags_code + FEATURE_CHECK_CFLAGS-libunwind-$(1) = -I$(LIBUNWIND_DIR)/include + FEATURE_CHECK_LDFLAGS-libunwind-$(1) = -L$(LIBUNWIND_DIR)/lib +endef + ifdef LIBUNWIND_DIR LIBUNWIND_CFLAGS = -I$(LIBUNWIND_DIR)/include LIBUNWIND_LDFLAGS = -L$(LIBUNWIND_DIR)/lib + LIBUNWIND_ARCHS = x86 x86_64 arm aarch64 debug-frame-arm debug-frame-aarch64 + $(foreach libunwind_arch,$(LIBUNWIND_ARCHS),$(call libunwind_arch_set_flags,$(libunwind_arch))) endif LIBUNWIND_LDFLAGS += $(LIBUNWIND_LIBS) -- 1.8.5.2
[PATCH v5 2/5] perf tools: Show warnings for unsupported cross-platform unwind
Currently, perf script uses host unwind methods to parse perf.data callchain info regardless of the target architecture. So we get wrong result without any warnings when unwinding callchains of x86(32-bit) on x86(64-bit) machine. This patch shows warning messages when we do remote unwind x86(32-bit) on other machines. Same thing for other platforms will be added in next patches. Common functions which will be used by both local unwind and remote unwind are separated into new file 'unwind-libunwind_common.c'. Signed-off-by: He Kuang --- tools/perf/arch/common.c | 2 +- tools/perf/arch/common.h | 1 + tools/perf/config/Makefile| 5 + tools/perf/util/Build | 1 + tools/perf/util/thread.c | 2 ++ tools/perf/util/unwind-libunwind_common.c | 34 +++ tools/perf/util/unwind.h | 5 + 7 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 tools/perf/util/unwind-libunwind_common.c diff --git a/tools/perf/arch/common.c b/tools/perf/arch/common.c index e83c8ce..fa090a9 100644 --- a/tools/perf/arch/common.c +++ b/tools/perf/arch/common.c @@ -102,7 +102,7 @@ static int lookup_triplets(const char *const *triplets, const char *name) * Return architecture name in a normalized form. * The conversion logic comes from the Makefile. */ -static const char *normalize_arch(char *arch) +const char *normalize_arch(char *arch) { if (!strcmp(arch, "x86_64")) return "x86"; diff --git a/tools/perf/arch/common.h b/tools/perf/arch/common.h index 7529cfb..6b01c73 100644 --- a/tools/perf/arch/common.h +++ b/tools/perf/arch/common.h @@ -6,5 +6,6 @@ extern const char *objdump_path; int perf_env__lookup_objdump(struct perf_env *env); +const char *normalize_arch(char *arch); #endif /* ARCH_PERF_COMMON_H */ diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index 6f9f566..c9e1625 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile @@ -354,6 +354,11 @@ ifeq ($(ARCH),powerpc) endif ifndef NO_LIBUNWIND + ifeq ($(feature-libunwind-x86), 1) +$(call detected,CONFIG_LIBUNWIND_X86) +CFLAGS += -DHAVE_LIBUNWIND_X86_SUPPORT + endif + ifneq ($(feature-libunwind), 1) msg := $(warning No libunwind found. Please install libunwind-dev[el] >= 1.1 and/or set LIBUNWIND_DIR); NO_LIBUNWIND := 1 diff --git a/tools/perf/util/Build b/tools/perf/util/Build index 8c6c8a0..25c31fb 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -100,6 +100,7 @@ libperf-$(CONFIG_DWARF) += dwarf-aux.o libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o libperf-$(CONFIG_LIBUNWIND) += unwind-libunwind.o +libperf-$(CONFIG_LIBUNWIND) += unwind-libunwind_common.o libperf-$(CONFIG_LIBBABELTRACE) += data-convert-bt.o diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 45fcb71..3043113 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c @@ -205,6 +205,8 @@ void thread__insert_map(struct thread *thread, struct map *map) { map_groups__fixup_overlappings(thread->mg, map, stderr); map_groups__insert(thread->mg, map); + + unwind__get_arch(thread, map); } static int thread__clone_map_groups(struct thread *thread, diff --git a/tools/perf/util/unwind-libunwind_common.c b/tools/perf/util/unwind-libunwind_common.c new file mode 100644 index 000..3946c99 --- /dev/null +++ b/tools/perf/util/unwind-libunwind_common.c @@ -0,0 +1,34 @@ +#include "thread.h" +#include "session.h" +#include "unwind.h" +#include "symbol.h" +#include "debug.h" +#include "arch/common.h" + +void unwind__get_arch(struct thread *thread, struct map *map) +{ + const char *arch; + enum dso_type dso_type; + + if (!thread->mg->machine->env) + return; + + dso_type = dso__type(map->dso, thread->mg->machine); + if (dso_type == DSO__TYPE_UNKNOWN) + return; + + if (thread->addr_space) + pr_debug("unwind: thread map already set, 64bit is %d, dso=%s\n", +dso_type == DSO__TYPE_64BIT, map->dso->name); + + arch = normalize_arch(thread->mg->machine->env->arch); + + if (!strcmp(arch, "x86")) { + if (dso_type != DSO__TYPE_64BIT) +#ifdef HAVE_LIBUNWIND_X86_SUPPORT + pr_err("unwind: target platform=%s is not implemented\n", arch); +#else + pr_err("unwind: target platform=%s is not supported\n", arch); +#endif + } +} diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h index 12790cf..889d630 100644 --- a/tools/perf/util/unwind.h +++ b/tools/perf/util/unwind.h @@ -24,6 +24,7 @@ int libunwind__arch_re
[PATCH v3 1/7 UPDATE2] perf tools: Find vdso with the consider of cross-platform
There's a problem in machine__findnew_vdso(), vdso buildid generated by a 32-bit machine stores it with the name 'vdso', but when processing buildid on a 64-bit machine with the same 'perf.data', perf will search for vdso named as 'vdso32' and get failed. This patch tries to find the exsiting dsos in machine->dsos by thread dso_type. 64-bit thread tries to find vdso with name 'vdso', because all 64-bit vdso is named as that. 32-bit thread first tries to find vdso with name 'vdso32' if this thread was run on 64-bit machine, if failed, then it tries 'vdso' which indicates that the thread was run on 32-bit machine when recording. Signed-off-by: He Kuang --- tools/perf/util/vdso.c | 40 +--- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/tools/perf/util/vdso.c b/tools/perf/util/vdso.c index 44d440d..8f81c41 100644 --- a/tools/perf/util/vdso.c +++ b/tools/perf/util/vdso.c @@ -134,8 +134,6 @@ static struct dso *__machine__addnew_vdso(struct machine *machine, const char *s return dso; } -#if BITS_PER_LONG == 64 - static enum dso_type machine__thread_dso_type(struct machine *machine, struct thread *thread) { @@ -156,6 +154,8 @@ static enum dso_type machine__thread_dso_type(struct machine *machine, return dso_type; } +#if BITS_PER_LONG == 64 + static int vdso__do_copy_compat(FILE *f, int fd) { char buf[4096]; @@ -283,8 +283,38 @@ static int __machine__findnew_vdso_compat(struct machine *machine, #endif +static struct dso *machine__find_vdso(struct machine *machine, + struct thread *thread) +{ + struct dso *dso = NULL; + enum dso_type dso_type; + + dso_type = machine__thread_dso_type(machine, thread); + switch (dso_type) { + case DSO__TYPE_32BIT: + dso = __dsos__find(&machine->dsos, DSO__NAME_VDSO32, true); + if (!dso) { + dso = __dsos__find(&machine->dsos, DSO__NAME_VDSO, + true); + if (dso_type != dso__type(dso, machine)) + dso = NULL; + } + break; + case DSO__TYPE_X32BIT: + dso = __dsos__find(&machine->dsos, DSO__NAME_VDSOX32, true); + break; + case DSO__TYPE_64BIT: + case DSO__TYPE_UNKNOWN: + default: + dso = __dsos__find(&machine->dsos, DSO__NAME_VDSO, true); + break; + } + + return dso; +} + struct dso *machine__findnew_vdso(struct machine *machine, - struct thread *thread __maybe_unused) + struct thread *thread) { struct vdso_info *vdso_info; struct dso *dso = NULL; @@ -297,6 +327,10 @@ struct dso *machine__findnew_vdso(struct machine *machine, if (!vdso_info) goto out_unlock; + dso = machine__find_vdso(machine, thread); + if (dso) + goto out_unlock; + #if BITS_PER_LONG == 64 if (__machine__findnew_vdso_compat(machine, thread, vdso_info, &dso)) goto out_unlock; -- 1.8.5.2
[PATCH v4 6/6] perf callchain: Support aarch64 cross-platform
Support aarch64 cross platform callchain unwind. Signed-off-by: He Kuang --- .../perf/arch/arm64/include/libunwind/libunwind-arch.h | 18 ++ tools/perf/arch/arm64/util/unwind-libunwind.c | 5 - tools/perf/config/Makefile | 12 tools/perf/util/Build | 4 tools/perf/util/unwind-libunwind_common.c | 10 ++ tools/perf/util/unwind.h | 3 +++ 6 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 tools/perf/arch/arm64/include/libunwind/libunwind-arch.h diff --git a/tools/perf/arch/arm64/include/libunwind/libunwind-arch.h b/tools/perf/arch/arm64/include/libunwind/libunwind-arch.h new file mode 100644 index 000..7bc8a00 --- /dev/null +++ b/tools/perf/arch/arm64/include/libunwind/libunwind-arch.h @@ -0,0 +1,18 @@ +#ifndef _LIBUNWIND_ARCH_H +#define _LIBUNWIND_ARCH_H + +#include +#include <../perf_regs.h> +#include <../../../../../../arch/arm64/include/uapi/asm/perf_regs.h> + +#define LIBUNWIND_AARCH64 +int libunwind__aarch64_reg_id(int regnum); + +#include <../../../arm64/util/unwind-libunwind.c> + +#define LIBUNWIND__ARCH_REG_ID libunwind__aarch64_reg_id + +#define UNWT_PREFIXUNW_PASTE(UNW_PASTE(_U, aarch64), _) +#define UNWT_OBJ(fn) UNW_PASTE(UNWT_PREFIX, fn) + +#endif /* _LIBUNWIND_ARCH_H */ diff --git a/tools/perf/arch/arm64/util/unwind-libunwind.c b/tools/perf/arch/arm64/util/unwind-libunwind.c index a87afa9..5b557a5 100644 --- a/tools/perf/arch/arm64/util/unwind-libunwind.c +++ b/tools/perf/arch/arm64/util/unwind-libunwind.c @@ -1,11 +1,14 @@ #include -#include #include "perf_regs.h" #include "../../util/unwind.h" #include "../../util/debug.h" +#ifndef LIBUNWIND_AARCH64 int libunwind__arch_reg_id(int regnum) +#else +int libunwind__aarch64_reg_id(int regnum) +#endif { switch (regnum) { case UNW_AARCH64_X0: diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index 3035dbf..d3b77d8 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile @@ -353,6 +353,18 @@ ifndef NO_LIBUNWIND have_libunwind = 1 endif + ifeq ($(feature-libunwind-aarch64), 1) +$(call detected,CONFIG_LIBUNWIND_AARCH64) +CFLAGS += -DHAVE_LIBUNWIND_AARCH64_SUPPORT +LDFLAGS += -lunwind -lunwind-aarch64 +have_libunwind = 1 +$(call feature_check,libunwind-debug-frame-aarch64) +ifneq ($(feature-libunwind-debug-frame-aarch64), 1) + msg := $(warning No debug_frame support found in libunwind-aarch64); + CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME_AARCH64 +endif + endif + ifneq ($(feature-libunwind), 1) msg := $(warning No libunwind found. Please install libunwind-dev[el] >= 1.1 and/or set LIBUNWIND_DIR); NO_LOCAL_LIBUNWIND := 1 diff --git a/tools/perf/util/Build b/tools/perf/util/Build index 2373130..f1b51a2 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -104,10 +104,14 @@ libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o libperf-$(CONFIG_LOCAL_LIBUNWIND)+= unwind-libunwind.o libperf-$(CONFIG_LIBUNWIND) += unwind-libunwind_common.o libperf-$(CONFIG_LIBUNWIND_X86) += unwind-libunwind_x86_32.o +libperf-$(CONFIG_LIBUNWIND_AARCH64) += unwind-libunwind_arm64.o $(OUTPUT)util/unwind-libunwind_x86_32.o: util/unwind-libunwind.c arch/x86/util/unwind-libunwind.c $(QUIET_CC)$(CC) $(CFLAGS) -DREMOTE_UNWIND_LIBUNWIND -Iarch/x86/include/libunwind -c -o $@ util/unwind-libunwind.c +$(OUTPUT)util/unwind-libunwind_arm64.o: util/unwind-libunwind.c arch/arm64/util/unwind-libunwind.c + $(QUIET_CC)$(CC) $(CFLAGS) -DREMOTE_UNWIND_LIBUNWIND -Iarch/arm64/include/libunwind -c -o $@ util/unwind-libunwind.c + libperf-$(CONFIG_LIBBABELTRACE) += data-convert-bt.o libperf-y += scripting-engines/ diff --git a/tools/perf/util/unwind-libunwind_common.c b/tools/perf/util/unwind-libunwind_common.c index 619c6c0..d19b062 100644 --- a/tools/perf/util/unwind-libunwind_common.c +++ b/tools/perf/util/unwind-libunwind_common.c @@ -89,6 +89,16 @@ void unwind__get_arch(struct thread *thread, struct map *map) #endif use_local_unwind = 0; } + } else if (!strcmp(arch, "arm64") || !strcmp(arch, "arm")) { + if (dso_type == DSO__TYPE_64BIT) { +#ifdef HAVE_LIBUNWIND_AARCH64_SUPPORT + register_unwind_libunwind_ops( + &_Uaarch64_unwind_libunwind_ops, thread); +#else + register_null_unwind_libunwind_ops(thread); +#endif + use_local_unwind = 0; + } } if (use_local_unwind) diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h index 73f4bd9..9748c36 100644 --- a/tools/perf/util/unwind.h +++ b/tools/perf/util/unwind.h @@ -55,6 +55,9 @@ register_
[PATCH v4 0/6] Add support for remote unwind
v3 url: http://thread.gmane.org/gmane.linux.kernel/2220387 Currently, perf script uses host unwind methods(local unwind) to parse perf.data callchain info regardless of the target architecture. So we get wrong result and no promotion when do remote unwind on other platforms/machines. This patchset checks whether a dso is 32-bit or 64-bit according to elf class info for each thread to let perf use the correct remote unwind methods instead. Only x86 and aarch64 is added in this patchset to show the work flow, other platforms can be added easily. We can see the right result for unwind info on different machines, for example: perf.data recorded on i686 qemu with '-g' option and parsed on x86_64 machine. before this patchset: hello 1219 [001] 72190.667975: probe:sys_close: (c1169d60) c1169d61 sys_close ([kernel.kallsyms]) c189c0d7 sysenter_past_esp ([kernel.kallsyms]) b777aba9 [unknown] ([vdso32]) after: (Add vdso into buildid-cache first by 'perf buildid-cache -a' and libraries are provided in symfs dir) hello 1219 [001] 72190.667975: probe:sys_close: (c1169d60) c1169d61 sys_close ([kernel.kallsyms]) c189c0d7 sysenter_past_esp ([kernel.kallsyms]) b777aba9 __kernel_vsyscall ([vdso32]) b76971cc close (/lib/libc-2.22.so) 804842e fib (/tmp/hello) 804849d main (/tmp/hello) b75d746e __libc_start_main (/lib/libc-2.22.so) 8048341 _start (/tmp/hello) v4: - Move reference of buildid dir to 'symfs/.debug' if --symfs is given. - Split makefile changes out of patch 'Add support for cross-platform unwind'. - Use existing code normalize_arch() for testing the arch of perf.data. v3: - Remove --vdso option, store vdso buildid in perf.data and let perf fetch it automatically. - Use existing dso__type() function to test if dso is 32-bit or 64-bit. v2: - Explain the reason why we can omit dwarf judgement when recording in commit message. - Elaborate on why we need to add a custom vdso path option, and change the type name to DSO_BINARY_TYPE__VDSO. - Hide the build tests status for cross platform unwind. - Keep generic version of libunwind-debug-frame test. - Put 32/64-bit test functions into separate patch. - Extract unwind related functions to unwind-libunwind.c and add new file for common parts used by both local and remote unwind. - Eliminate most of the ifdefs in .c file. Thanks. He Kuang (6): perf tools: Set buildid dir under symfs when --symfs is provided perf tools: Promote proper messages for cross-platform unwind perf tools: Separate local and remote unwind support detection perf callchain: Add support for cross-platform unwind perf callchain: Support x86 target platform perf callchain: Support aarch64 cross-platform .../arch/arm64/include/libunwind/libunwind-arch.h | 18 tools/perf/arch/arm64/util/unwind-libunwind.c | 5 +- tools/perf/arch/common.c | 2 +- tools/perf/arch/common.h | 1 + .../arch/x86/include/libunwind/libunwind-arch.h| 18 tools/perf/arch/x86/util/unwind-libunwind.c| 12 ++- tools/perf/builtin-annotate.c | 5 +- tools/perf/builtin-diff.c | 5 +- tools/perf/builtin-report.c| 5 +- tools/perf/builtin-script.c| 5 +- tools/perf/builtin-timechart.c | 5 +- tools/perf/config/Makefile | 37 ++- tools/perf/util/Build | 13 ++- tools/perf/util/dso.c | 4 +- tools/perf/util/symbol.c | 23 + tools/perf/util/symbol.h | 2 + tools/perf/util/thread.c | 7 +- tools/perf/util/thread.h | 14 ++- tools/perf/util/unwind-libunwind.c | 48 +++-- tools/perf/util/unwind-libunwind_common.c | 109 + tools/perf/util/unwind.h | 45 +++-- 21 files changed, 341 insertions(+), 42 deletions(-) create mode 100644 tools/perf/arch/arm64/include/libunwind/libunwind-arch.h create mode 100644 tools/perf/arch/x86/include/libunwind/libunwind-arch.h create mode 100644 tools/perf/util/unwind-libunwind_common.c -- 1.8.5.2
[PATCH v4 1/6] perf tools: Set buildid dir under symfs when --symfs is provided
This patch moves the reference of buildid dir to 'symfs/.debug' and skips the local buildid dir when '--symfs' is given, so that every single file opened by perf is relateive to symfs directory now. Signed-off-by: He Kuang --- tools/perf/builtin-annotate.c | 5 +++-- tools/perf/builtin-diff.c | 5 +++-- tools/perf/builtin-report.c| 5 +++-- tools/perf/builtin-script.c| 5 +++-- tools/perf/builtin-timechart.c | 5 +++-- tools/perf/util/dso.c | 4 +--- tools/perf/util/symbol.c | 23 +++ tools/perf/util/symbol.h | 2 ++ 8 files changed, 41 insertions(+), 13 deletions(-) diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 8141583..25c8173 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -324,8 +324,9 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused) OPT_BOOLEAN(0, "skip-missing", &annotate.skip_missing, "Skip symbols that cannot be annotated"), OPT_STRING('C', "cpu", &annotate.cpu_list, "cpu", "list of cpus to profile"), - OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", - "Look for files with symbols relative to this directory"), + OPT_CALLBACK(0, "symfs", NULL, "directory", +"Look for files with symbols relative to this directory", +symbol__config_symfs), OPT_BOOLEAN(0, "source", &symbol_conf.annotate_src, "Interleave source code with assembly code (default)"), OPT_BOOLEAN(0, "asm-raw", &symbol_conf.annotate_asm_raw, diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index 9ce354f..f7645a4 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -812,8 +812,9 @@ static const struct option options[] = { OPT_STRING_NOEMPTY('t', "field-separator", &symbol_conf.field_sep, "separator", "separator for columns, no spaces will be added between " "columns '.' is reserved."), - OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", - "Look for files with symbols relative to this directory"), + OPT_CALLBACK(0, "symfs", NULL, "directory", +"Look for files with symbols relative to this directory", +symbol__config_symfs), OPT_UINTEGER('o', "order", &sort_compute, "Specify compute sorting."), OPT_CALLBACK(0, "percentage", NULL, "relative|absolute", "How to display percentage of filtered entries", parse_filter_percentage), diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 87d40e3..84b4f730 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -770,8 +770,9 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) "columns '.' is reserved."), OPT_BOOLEAN('U', "hide-unresolved", &symbol_conf.hide_unresolved, "Only display entries resolved to a symbol"), - OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", - "Look for files with symbols relative to this directory"), + OPT_CALLBACK(0, "symfs", NULL, "directory", +"Look for files with symbols relative to this directory", +symbol__config_symfs), OPT_STRING('C', "cpu", &report.cpu_list, "cpu", "list of cpus to profile"), OPT_BOOLEAN('I', "show-info", &report.show_full_info, diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index efca816..a8bf0e2 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -2010,8 +2010,9 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) "file", "kallsyms pathname"), OPT_BOOLEAN('G', "hide-call-graph", &no_callchain, "When printing symbols do not display call chain"), - OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", - "Look for files with symbols relative to this directory"), + OPT_CALLBACK(0, "symfs", NULL, "directory", +"Look for files with symbols relative to this directory",
[PATCH v4 4/6] perf callchain: Add support for cross-platform unwind
Use thread specific unwind ops to unwind cross-platform callchains. Before this patch, unwind methods is suitable for local unwind, this patch changes the fixed methods to thread/map related. Each time a map is inserted, we find the target arch and see if this platform can be remote unwind. In this patch, we test for x86 platform and only show proper messages. The real unwind methods are not implemented, will be introduced in next patch. Signed-off-by: He Kuang --- tools/perf/util/thread.c | 5 +-- tools/perf/util/thread.h | 14 +- tools/perf/util/unwind-libunwind.c| 48 ++--- tools/perf/util/unwind-libunwind_common.c | 71 +-- tools/perf/util/unwind.h | 32 +- 5 files changed, 145 insertions(+), 25 deletions(-) diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 3043113..4e1aaf5 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c @@ -43,9 +43,6 @@ struct thread *thread__new(pid_t pid, pid_t tid) thread->cpu = -1; INIT_LIST_HEAD(&thread->comm_list); - if (unwind__prepare_access(thread) < 0) - goto err_thread; - comm_str = malloc(32); if (!comm_str) goto err_thread; @@ -59,6 +56,8 @@ struct thread *thread__new(pid_t pid, pid_t tid) list_add(&comm->list, &thread->comm_list); atomic_set(&thread->refcnt, 1); RB_CLEAR_NODE(&thread->rb_node); + + register_null_unwind_libunwind_ops(thread); } return thread; diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h index 45fba13..de8e42e 100644 --- a/tools/perf/util/thread.h +++ b/tools/perf/util/thread.h @@ -15,6 +15,17 @@ struct thread_stack; +struct unwind_entry; +typedef int (*unwind_entry_cb_t)(struct unwind_entry *entry, void *arg); +struct unwind_libunwind_ops { + int (*prepare_access)(struct thread *thread); + void (*flush_access)(struct thread *thread); + void (*finish_access)(struct thread *thread); + int (*get_entries)(unwind_entry_cb_t cb, void *arg, + struct thread *thread, + struct perf_sample *data, int max_stack); +}; + struct thread { union { struct rb_node rb_node; @@ -36,7 +47,8 @@ struct thread { void*priv; struct thread_stack *ts; #ifdef HAVE_LIBUNWIND_SUPPORT - unw_addr_space_taddr_space; + unw_addr_space_taddr_space; + struct unwind_libunwind_ops *unwind_libunwind_ops; #endif }; diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c index 63687d3..d3a2ec44 100644 --- a/tools/perf/util/unwind-libunwind.c +++ b/tools/perf/util/unwind-libunwind.c @@ -22,6 +22,9 @@ #include #include #include +#ifdef REMOTE_UNWIND_LIBUNWIND +#include "libunwind-arch.h" +#endif #include #include #include "callchain.h" @@ -34,6 +37,21 @@ #include "debug.h" #include "asm/bug.h" +#ifndef REMOTE_UNWIND_LIBUNWIND + #define LIBUNWIND__ARCH_REG_ID libunwind__arch_reg_id + #define LOCAL_UNWIND_LIBUNWIND + #undef UNWT_OBJ + #define UNWT_OBJ(x) _##x +#else + #undef NO_LIBUNWIND_DEBUG_FRAME + #if defined(LIBUNWIND_ARM) && !defined(NO_LIBUNWIND_DEBUG_FRAME_ARM) + #elif defined(LIBUNWIND_AARCH64) &&\ + defined(NO_LIBUNWIND_DEBUG_FRAME_ARM_AARCH64) + #else +#define NO_LIBUNWIND_DEBUG_FRAME + #endif +#endif + extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, unw_word_t ip, @@ -508,7 +526,7 @@ static int access_reg(unw_addr_space_t __maybe_unused as, return 0; } - id = libunwind__arch_reg_id(regnum); + id = LIBUNWIND__ARCH_REG_ID(regnum); if (id < 0) return -EINVAL; @@ -579,7 +597,7 @@ static unw_accessors_t accessors = { .get_proc_name = get_proc_name, }; -int unwind__prepare_access(struct thread *thread) +static int UNWT_OBJ(_unwind__prepare_access)(struct thread *thread) { if (callchain_param.record_mode != CALLCHAIN_DWARF) return 0; @@ -594,7 +612,7 @@ int unwind__prepare_access(struct thread *thread) return 0; } -void unwind__flush_access(struct thread *thread) +static void UNWT_OBJ(_unwind__flush_access)(struct thread *thread) { if (callchain_param.record_mode != CALLCHAIN_DWARF) return; @@ -602,7 +620,7 @@ void unwind__flush_access(struct thread *thread) unw_flush_cache(thread->addr_space, 0, 0); } -void unwind__finish_access(struct thread *thread) +static void UNWT_OBJ(_unwind__finish_access)(struct thread *thread)
[PATCH v4 3/6] perf tools: Separate local and remote unwind support detection
This patch changes original CONFIG_LIBUNWIND/NO_LIBUNWIND to CONFIG_LOCAL_LIBUNWIND/NO_LOCAL_LIBUNWIND for retaining local unwind features. CONFIG_LIBUNWIND stands for either local or remote or both unwind are supported and NO_LIBUNWIND means neither local nor remote libunwind are supported. Signed-off-by: He Kuang --- tools/perf/config/Makefile | 21 ++--- tools/perf/util/Build | 2 +- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index a86b864..3035dbf 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile @@ -345,16 +345,28 @@ ifeq ($(ARCH),powerpc) endif ifndef NO_LIBUNWIND + have_libunwind = ifeq ($(feature-libunwind-x86), 1) -LIBUNWIND_LIBS += -lunwind-x86 $(call detected,CONFIG_LIBUNWIND_X86) CFLAGS += -DHAVE_LIBUNWIND_X86_SUPPORT +LDFLAGS += -lunwind -lunwind-x86 +have_libunwind = 1 endif ifneq ($(feature-libunwind), 1) msg := $(warning No libunwind found. Please install libunwind-dev[el] >= 1.1 and/or set LIBUNWIND_DIR); +NO_LOCAL_LIBUNWIND := 1 + else +have_libunwind = 1 +CFLAGS += -DHAVE_LIBUNWIND_LOCAL_SUPPORT +$(call detected,CONFIG_LOCAL_LIBUNWIND) + endif + + ifneq ($(have_libunwind), 1) NO_LIBUNWIND := 1 endif +else + NO_LOCAL_LIBUNWIND := 1 endif ifndef NO_LIBBPF @@ -392,7 +404,7 @@ else NO_DWARF_UNWIND := 1 endif -ifndef NO_LIBUNWIND +ifndef NO_LOCAL_LIBUNWIND ifeq ($(ARCH),$(filter $(ARCH),arm arm64)) $(call feature_check,libunwind-debug-frame) ifneq ($(feature-libunwind-debug-frame), 1) @@ -403,12 +415,15 @@ ifndef NO_LIBUNWIND # non-ARM has no dwarf_find_debug_frame() function: CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME endif - CFLAGS += -DHAVE_LIBUNWIND_SUPPORT EXTLIBS += $(LIBUNWIND_LIBS) CFLAGS += $(LIBUNWIND_CFLAGS) LDFLAGS += $(LIBUNWIND_LDFLAGS) endif +ifndef NO_LIBUNWIND + CFLAGS += -DHAVE_LIBUNWIND_SUPPORT +endif + ifndef NO_LIBAUDIT ifneq ($(feature-libaudit), 1) msg := $(warning No libaudit.h found, disables 'trace' tool, please install audit-libs-devel or libaudit-dev); diff --git a/tools/perf/util/Build b/tools/perf/util/Build index 25c31fb..ce69721 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -99,7 +99,7 @@ libperf-$(CONFIG_DWARF) += probe-finder.o libperf-$(CONFIG_DWARF) += dwarf-aux.o libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o -libperf-$(CONFIG_LIBUNWIND) += unwind-libunwind.o +libperf-$(CONFIG_LOCAL_LIBUNWIND)+= unwind-libunwind.o libperf-$(CONFIG_LIBUNWIND) += unwind-libunwind_common.o libperf-$(CONFIG_LIBBABELTRACE) += data-convert-bt.o -- 1.8.5.2
[PATCH v4 5/6] perf callchain: Support x86 target platform
Support x86(32-bit) cross platform callchain unwind. Signed-off-by: He Kuang --- tools/perf/arch/x86/include/libunwind/libunwind-arch.h | 18 ++ tools/perf/arch/x86/util/unwind-libunwind.c| 12 +--- tools/perf/util/Build | 6 ++ tools/perf/util/unwind-libunwind_common.c | 6 -- tools/perf/util/unwind.h | 5 + 5 files changed, 42 insertions(+), 5 deletions(-) create mode 100644 tools/perf/arch/x86/include/libunwind/libunwind-arch.h diff --git a/tools/perf/arch/x86/include/libunwind/libunwind-arch.h b/tools/perf/arch/x86/include/libunwind/libunwind-arch.h new file mode 100644 index 000..265f14d --- /dev/null +++ b/tools/perf/arch/x86/include/libunwind/libunwind-arch.h @@ -0,0 +1,18 @@ +#ifndef _LIBUNWIND_ARCH_H +#define _LIBUNWIND_ARCH_H + +#include +#include <../perf_regs.h> +#include <../../../../../../arch/x86/include/uapi/asm/perf_regs.h> + +#define LIBUNWIND_X86_32 +int libunwind__x86_reg_id(int regnum); + +#include <../../../x86/util/unwind-libunwind.c> + +#define LIBUNWIND__ARCH_REG_ID libunwind__x86_reg_id + +#define UNWT_PREFIXUNW_PASTE(UNW_PASTE(_U, x86), _) +#define UNWT_OBJ(fn) UNW_PASTE(UNWT_PREFIX, fn) + +#endif /* _LIBUNWIND_ARCH_H */ diff --git a/tools/perf/arch/x86/util/unwind-libunwind.c b/tools/perf/arch/x86/util/unwind-libunwind.c index db25e93..a4f5449 100644 --- a/tools/perf/arch/x86/util/unwind-libunwind.c +++ b/tools/perf/arch/x86/util/unwind-libunwind.c @@ -5,7 +5,7 @@ #include "../../util/unwind.h" #include "../../util/debug.h" -#ifdef HAVE_ARCH_X86_64_SUPPORT +#if !defined(LIBUNWIND_X86_32) && defined(HAVE_ARCH_X86_64_SUPPORT) int libunwind__arch_reg_id(int regnum) { int id; @@ -69,8 +69,14 @@ int libunwind__arch_reg_id(int regnum) return id; } -#else +#endif + +#if defined(LIBUNWIND_X86_32) || !defined(HAVE_ARCH_X86_64_SUPPORT) +#ifndef LIBUNWIND_X86_32 int libunwind__arch_reg_id(int regnum) +#else +int libunwind__x86_reg_id(int regnum) +#endif { int id; @@ -109,4 +115,4 @@ int libunwind__arch_reg_id(int regnum) return id; } -#endif /* HAVE_ARCH_X86_64_SUPPORT */ +#endif diff --git a/tools/perf/util/Build b/tools/perf/util/Build index ce69721..2373130 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -1,3 +1,5 @@ +include ../scripts/Makefile.include + libperf-y += alias.o libperf-y += annotate.o libperf-y += build-id.o @@ -101,6 +103,10 @@ libperf-$(CONFIG_DWARF) += dwarf-aux.o libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o libperf-$(CONFIG_LOCAL_LIBUNWIND)+= unwind-libunwind.o libperf-$(CONFIG_LIBUNWIND) += unwind-libunwind_common.o +libperf-$(CONFIG_LIBUNWIND_X86) += unwind-libunwind_x86_32.o + +$(OUTPUT)util/unwind-libunwind_x86_32.o: util/unwind-libunwind.c arch/x86/util/unwind-libunwind.c + $(QUIET_CC)$(CC) $(CFLAGS) -DREMOTE_UNWIND_LIBUNWIND -Iarch/x86/include/libunwind -c -o $@ util/unwind-libunwind.c libperf-$(CONFIG_LIBBABELTRACE) += data-convert-bt.o diff --git a/tools/perf/util/unwind-libunwind_common.c b/tools/perf/util/unwind-libunwind_common.c index f44833b..619c6c0 100644 --- a/tools/perf/util/unwind-libunwind_common.c +++ b/tools/perf/util/unwind-libunwind_common.c @@ -82,9 +82,11 @@ void unwind__get_arch(struct thread *thread, struct map *map) if (!strcmp(arch, "x86")) { if (dso_type != DSO__TYPE_64BIT) { #ifdef HAVE_LIBUNWIND_X86_SUPPORT - pr_err("unwind: target platform=%s is not implemented\n", arch); -#endif + register_unwind_libunwind_ops( + &_Ux86_unwind_libunwind_ops, thread); +#else register_null_unwind_libunwind_ops(thread); +#endif use_local_unwind = 0; } } diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h index 1187950..73f4bd9 100644 --- a/tools/perf/util/unwind.h +++ b/tools/perf/util/unwind.h @@ -51,6 +51,11 @@ static inline void unwind__get_arch(struct thread *thread __maybe_unused, static inline void register_null_unwind_libunwind_ops(struct thread *thread __maybe_unused) {} #endif + +#ifdef HAVE_LIBUNWIND_X86_SUPPORT +extern struct unwind_libunwind_ops _Ux86_unwind_libunwind_ops; +#endif + #else static inline int unwind__get_entries(unwind_entry_cb_t cb __maybe_unused, -- 1.8.5.2
[PATCH v4 2/6] perf tools: Promote proper messages for cross-platform unwind
Currently, perf script uses host unwind methods to parse perf.data callchain info regardless of the target architecture. So we get wrong result and no promotion when unwinding callchains of x86(32-bit) on x86(64-bit) machine. This patch shows proper error messages when we do remote unwind x86(32-bit) on other machines. Same thing for other platforms will be added in next patches. Common functions which will be used by both local unwind and remote unwind are separated into new file 'unwind-libunwind_common.c'. Signed-off-by: He Kuang --- tools/perf/arch/common.c | 2 +- tools/perf/arch/common.h | 1 + tools/perf/config/Makefile| 6 ++ tools/perf/util/Build | 1 + tools/perf/util/thread.c | 2 ++ tools/perf/util/unwind-libunwind_common.c | 34 +++ tools/perf/util/unwind.h | 5 + 7 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 tools/perf/util/unwind-libunwind_common.c diff --git a/tools/perf/arch/common.c b/tools/perf/arch/common.c index e83c8ce..fa090a9 100644 --- a/tools/perf/arch/common.c +++ b/tools/perf/arch/common.c @@ -102,7 +102,7 @@ static int lookup_triplets(const char *const *triplets, const char *name) * Return architecture name in a normalized form. * The conversion logic comes from the Makefile. */ -static const char *normalize_arch(char *arch) +const char *normalize_arch(char *arch) { if (!strcmp(arch, "x86_64")) return "x86"; diff --git a/tools/perf/arch/common.h b/tools/perf/arch/common.h index 7529cfb..6b01c73 100644 --- a/tools/perf/arch/common.h +++ b/tools/perf/arch/common.h @@ -6,5 +6,6 @@ extern const char *objdump_path; int perf_env__lookup_objdump(struct perf_env *env); +const char *normalize_arch(char *arch); #endif /* ARCH_PERF_COMMON_H */ diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index 1e46277..a86b864 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile @@ -345,6 +345,12 @@ ifeq ($(ARCH),powerpc) endif ifndef NO_LIBUNWIND + ifeq ($(feature-libunwind-x86), 1) +LIBUNWIND_LIBS += -lunwind-x86 +$(call detected,CONFIG_LIBUNWIND_X86) +CFLAGS += -DHAVE_LIBUNWIND_X86_SUPPORT + endif + ifneq ($(feature-libunwind), 1) msg := $(warning No libunwind found. Please install libunwind-dev[el] >= 1.1 and/or set LIBUNWIND_DIR); NO_LIBUNWIND := 1 diff --git a/tools/perf/util/Build b/tools/perf/util/Build index 8c6c8a0..25c31fb 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -100,6 +100,7 @@ libperf-$(CONFIG_DWARF) += dwarf-aux.o libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o libperf-$(CONFIG_LIBUNWIND) += unwind-libunwind.o +libperf-$(CONFIG_LIBUNWIND) += unwind-libunwind_common.o libperf-$(CONFIG_LIBBABELTRACE) += data-convert-bt.o diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 45fcb71..3043113 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c @@ -205,6 +205,8 @@ void thread__insert_map(struct thread *thread, struct map *map) { map_groups__fixup_overlappings(thread->mg, map, stderr); map_groups__insert(thread->mg, map); + + unwind__get_arch(thread, map); } static int thread__clone_map_groups(struct thread *thread, diff --git a/tools/perf/util/unwind-libunwind_common.c b/tools/perf/util/unwind-libunwind_common.c new file mode 100644 index 000..3946c99 --- /dev/null +++ b/tools/perf/util/unwind-libunwind_common.c @@ -0,0 +1,34 @@ +#include "thread.h" +#include "session.h" +#include "unwind.h" +#include "symbol.h" +#include "debug.h" +#include "arch/common.h" + +void unwind__get_arch(struct thread *thread, struct map *map) +{ + const char *arch; + enum dso_type dso_type; + + if (!thread->mg->machine->env) + return; + + dso_type = dso__type(map->dso, thread->mg->machine); + if (dso_type == DSO__TYPE_UNKNOWN) + return; + + if (thread->addr_space) + pr_debug("unwind: thread map already set, 64bit is %d, dso=%s\n", +dso_type == DSO__TYPE_64BIT, map->dso->name); + + arch = normalize_arch(thread->mg->machine->env->arch); + + if (!strcmp(arch, "x86")) { + if (dso_type != DSO__TYPE_64BIT) +#ifdef HAVE_LIBUNWIND_X86_SUPPORT + pr_err("unwind: target platform=%s is not implemented\n", arch); +#else + pr_err("unwind: target platform=%s is not supported\n", arch); +#endif + } +} diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h index 12790cf..889d630 100644 --- a/tools/perf/util/unwind.h +++ b/tools/perf/util/unwind.h @@ -24,6 +
[PATCH v6 11/11] perf callchain: Support aarch64 cross-platform
Support aarch64 cross platform callchain unwind. Signed-off-by: He Kuang --- tools/perf/arch/Build | 1 + tools/perf/arch/arm64/util/unwind-libunwind.c | 4 +++- .../perf/arch/arm64/util/unwind-libunwind_arm64.c | 22 ++ tools/perf/config/Makefile | 12 tools/perf/util/unwind-libunwind.c | 6 +- tools/perf/util/unwind.h | 10 ++ 6 files changed, 53 insertions(+), 2 deletions(-) create mode 100644 tools/perf/arch/arm64/util/unwind-libunwind_arm64.c diff --git a/tools/perf/arch/Build b/tools/perf/arch/Build index 3fc4af1..bc49295 100644 --- a/tools/perf/arch/Build +++ b/tools/perf/arch/Build @@ -1,3 +1,4 @@ libperf-y += common.o libperf-y += $(ARCH)/ libperf-$(CONFIG_LIBUNWIND_X86) += x86/util/unwind-libunwind_x86_32.o +libperf-$(CONFIG_LIBUNWIND_AARCH64) += arm64/util/unwind-libunwind_arm64.o diff --git a/tools/perf/arch/arm64/util/unwind-libunwind.c b/tools/perf/arch/arm64/util/unwind-libunwind.c index a87afa9..c116b71 100644 --- a/tools/perf/arch/arm64/util/unwind-libunwind.c +++ b/tools/perf/arch/arm64/util/unwind-libunwind.c @@ -1,11 +1,13 @@ +#ifndef REMOTE_UNWIND_LIBUNWIND #include #include #include "perf_regs.h" #include "../../util/unwind.h" #include "../../util/debug.h" +#endif -int libunwind__arch_reg_id(int regnum) +int LIBUNWIND__ARCH_REG_ID(int regnum) { switch (regnum) { case UNW_AARCH64_X0: diff --git a/tools/perf/arch/arm64/util/unwind-libunwind_arm64.c b/tools/perf/arch/arm64/util/unwind-libunwind_arm64.c new file mode 100644 index 000..ea9e7d1 --- /dev/null +++ b/tools/perf/arch/arm64/util/unwind-libunwind_arm64.c @@ -0,0 +1,22 @@ +#define REMOTE_UNWIND_LIBUNWIND + +#define LIBUNWIND__ARCH_REG_ID libunwind__arm64_reg_id + +#include "unwind.h" +#include "debug.h" +#include "libunwind-aarch64.h" +#include <../../../../../arch/arm64/include/uapi/asm/perf_regs.h> +#include "unwind-libunwind.c" + +#undef NO_LIBUNWIND_DEBUG_FRAME +#ifdef NO_LIBUNWIND_DEBUG_FRAME_AARCH64 +#define NO_LIBUNWIND_DEBUG_FRAME +#endif + +#include "util/unwind-libunwind-local.c" + +int register_arm64_unwind_libunwind_ops(struct thread *thread) +{ + thread->unwind_libunwind_ops = &_unwind_libunwind_ops; + return 0; +} diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index e156f76..bb5aea8 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile @@ -363,6 +363,18 @@ ifndef NO_LIBUNWIND have_libunwind = 1 endif + ifeq ($(feature-libunwind-aarch64), 1) +$(call detected,CONFIG_LIBUNWIND_AARCH64) +CFLAGS += -DHAVE_LIBUNWIND_AARCH64_SUPPORT +LDFLAGS += -lunwind-aarch64 +have_libunwind = 1 +$(call feature_check,libunwind-debug-frame-aarch64) +ifneq ($(feature-libunwind-debug-frame-aarch64), 1) + msg := $(warning No debug_frame support found in libunwind-aarch64); + CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME_AARCH64 +endif + endif + ifneq ($(feature-libunwind), 1) msg := $(warning No libunwind found. Please install libunwind-dev[el] >= 1.1 and/or set LIBUNWIND_DIR); NO_LOCAL_LIBUNWIND := 1 diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c index c1d9d36..5930865 100644 --- a/tools/perf/util/unwind-libunwind.c +++ b/tools/perf/util/unwind-libunwind.c @@ -25,9 +25,13 @@ int unwind__prepare_access(struct thread *thread, struct map *map) arch = normalize_arch(thread->mg->machine->env->arch); - if (!strcmp(arch, "x86")) + if (!strcmp(arch, "x86")) { if (dso_type != DSO__TYPE_64BIT) register_func = register_x86_32_unwind_libunwind_ops; + } else if (!strcmp(arch, "arm64") || !strcmp(arch, "arm")) { + if (dso_type == DSO__TYPE_64BIT) + register_func = register_arm64_unwind_libunwind_ops; + } if (register_func) { ret = register_func(thread); diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h index 43f9f66..e203aa9 100644 --- a/tools/perf/util/unwind.h +++ b/tools/perf/util/unwind.h @@ -56,6 +56,16 @@ register_x86_32_unwind_libunwind_ops(struct thread *thread __maybe_unused) } #endif +#ifdef HAVE_LIBUNWIND_AARCH64_SUPPORT +int register_arm64_unwind_libunwind_ops(struct thread *thread); +#else +static inline int +register_arm64_unwind_libunwind_ops(struct thread *thread __maybe_unused) +{ + return -1; +} +#endif + #else static inline int unwind__get_entries(unwind_entry_cb_t cb __maybe_unused, -- 1.8.5.2
[PATCH v6 06/11] perf tools: Extract local libunwind code out of unwind-libunwind.c
This patch extracts codes related to specific arithecture out of unwind-libunwind.c. The extrated part are only built if local libunwind is supported. Signed-off-by: He Kuang --- tools/perf/util/Build| 1 + tools/perf/util/unwind-libunwind-local.c | 677 ++ tools/perf/util/unwind-libunwind.c | 694 +-- 3 files changed, 679 insertions(+), 693 deletions(-) create mode 100644 tools/perf/util/unwind-libunwind-local.c diff --git a/tools/perf/util/Build b/tools/perf/util/Build index 8c6c8a0..004fb1d 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -99,6 +99,7 @@ libperf-$(CONFIG_DWARF) += probe-finder.o libperf-$(CONFIG_DWARF) += dwarf-aux.o libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o +libperf-$(CONFIG_LOCAL_LIBUNWIND)+= unwind-libunwind-local.o libperf-$(CONFIG_LIBUNWIND) += unwind-libunwind.o libperf-$(CONFIG_LIBBABELTRACE) += data-convert-bt.o diff --git a/tools/perf/util/unwind-libunwind-local.c b/tools/perf/util/unwind-libunwind-local.c new file mode 100644 index 000..5599adc --- /dev/null +++ b/tools/perf/util/unwind-libunwind-local.c @@ -0,0 +1,677 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "callchain.h" +#include "thread.h" +#include "session.h" +#include "perf_regs.h" +#include "unwind.h" +#include "symbol.h" +#include "util.h" +#include "debug.h" +#include "asm/bug.h" + +extern int +UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, + unw_word_t ip, + unw_dyn_info_t *di, + unw_proc_info_t *pi, + int need_unwind_info, void *arg); + +#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table) + +extern int +UNW_OBJ(dwarf_find_debug_frame) (int found, unw_dyn_info_t *di_debug, +unw_word_t ip, +unw_word_t segbase, +const char *obj_name, unw_word_t start, +unw_word_t end); + +#define dwarf_find_debug_frame UNW_OBJ(dwarf_find_debug_frame) + +#define DW_EH_PE_FORMAT_MASK 0x0f/* format of the encoded value */ +#define DW_EH_PE_APPL_MASK 0x70/* how the value is to be applied */ + +/* Pointer-encoding formats: */ +#define DW_EH_PE_omit 0xff +#define DW_EH_PE_ptr 0x00/* pointer-sized unsigned value */ +#define DW_EH_PE_udata40x03/* unsigned 32-bit value */ +#define DW_EH_PE_udata80x04/* unsigned 64-bit value */ +#define DW_EH_PE_sdata40x0b/* signed 32-bit value */ +#define DW_EH_PE_sdata80x0c/* signed 64-bit value */ + +/* Pointer-encoding application: */ +#define DW_EH_PE_absptr0x00/* absolute value */ +#define DW_EH_PE_pcrel 0x10/* rel. to addr. of encoded value */ + +/* + * The following are not documented by LSB v1.3, yet they are used by + * GCC, presumably they aren't documented by LSB since they aren't + * used on Linux: + */ +#define DW_EH_PE_funcrel 0x40/* start-of-procedure-relative */ +#define DW_EH_PE_aligned 0x50/* aligned pointer */ + +/* Flags intentionaly not handled, since they're not needed: + * #define DW_EH_PE_indirect 0x80 + * #define DW_EH_PE_uleb128 0x01 + * #define DW_EH_PE_udata20x02 + * #define DW_EH_PE_sleb128 0x09 + * #define DW_EH_PE_sdata20x0a + * #define DW_EH_PE_textrel 0x20 + * #define DW_EH_PE_datarel 0x30 + */ + +struct unwind_info { + struct perf_sample *sample; + struct machine *machine; + struct thread *thread; +}; + +#define dw_read(ptr, type, end) ({ \ + type *__p = (type *) ptr; \ + type __v; \ + if ((__p + 1) > (type *) end) \ + return -EINVAL; \ + __v = *__p++; \ + ptr = (typeof(ptr)) __p;\ + __v;\ + }) + +static int __dw_read_encoded_value(u8 **p, u8 *end, u64 *val, + u8 encoding) +{ + u8 *cur = *p; + *val = 0; + + switch (encoding) { + case DW_EH_PE_omit: + *val = 0; + goto out; + case DW_EH_PE_ptr: + *val = dw_read(cur, unsigned long, end); + goto out; + default: + break; + } + + switch (encoding & DW_EH_PE_APPL_MASK) { + case DW_EH_PE_absptr: + break; + case DW_EH_PE_pcrel: + *val = (unsigned long) cur; + break; + default: + return -EINVAL; + }
[PATCH v6 07/11] perf tools: Export normalize_arch() function
Export normalize_arch() function, so other part of perf can get normalized form of arch string. Signed-off-by: He Kuang --- tools/perf/arch/common.c | 2 +- tools/perf/arch/common.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/perf/arch/common.c b/tools/perf/arch/common.c index e83c8ce..fa090a9 100644 --- a/tools/perf/arch/common.c +++ b/tools/perf/arch/common.c @@ -102,7 +102,7 @@ static int lookup_triplets(const char *const *triplets, const char *name) * Return architecture name in a normalized form. * The conversion logic comes from the Makefile. */ -static const char *normalize_arch(char *arch) +const char *normalize_arch(char *arch) { if (!strcmp(arch, "x86_64")) return "x86"; diff --git a/tools/perf/arch/common.h b/tools/perf/arch/common.h index 7529cfb..6b01c73 100644 --- a/tools/perf/arch/common.h +++ b/tools/perf/arch/common.h @@ -6,5 +6,6 @@ extern const char *objdump_path; int perf_env__lookup_objdump(struct perf_env *env); +const char *normalize_arch(char *arch); #endif /* ARCH_PERF_COMMON_H */ -- 1.8.5.2
[PATCH v6 04/11] perf tools: Move unwind__prepare_access from thread_new into thread__insert_map
For determine the libunwind methods to use, we should get the 32bit/64bit information from maps of a thread. When a thread is newly created, the information is not prepared. This patch moves unwind__prepare_access() into thread__insert_map() so we can get the information we need from maps. Signed-off-by: He Kuang --- tools/perf/util/thread.c | 7 ++- tools/perf/util/unwind-libunwind.c | 7 +++ 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 6d3900c..045477d 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c @@ -43,11 +43,6 @@ struct thread *thread__new(pid_t pid, pid_t tid) thread->cpu = -1; INIT_LIST_HEAD(&thread->comm_list); - register_local_unwind_libunwind_ops(thread); - - if (unwind__prepare_access(thread) < 0) - goto err_thread; - comm_str = malloc(32); if (!comm_str) goto err_thread; @@ -207,6 +202,8 @@ void thread__insert_map(struct thread *thread, struct map *map) { map_groups__fixup_overlappings(thread->mg, map, stderr); map_groups__insert(thread->mg, map); + + unwind__prepare_access(thread); } static int thread__clone_map_groups(struct thread *thread, diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c index 0277b22..93d2d8e 100644 --- a/tools/perf/util/unwind-libunwind.c +++ b/tools/perf/util/unwind-libunwind.c @@ -695,10 +695,9 @@ void register_local_unwind_libunwind_ops(struct thread *thread) int unwind__prepare_access(struct thread *thread) { - if (thread->unwind_libunwind_ops) - return thread->unwind_libunwind_ops->prepare_access(thread); - else - return 0; + register_local_unwind_libunwind_ops(thread); + + return thread->unwind_libunwind_ops->prepare_access(thread); } void unwind__flush_access(struct thread *thread) -- 1.8.5.2
[PATCH v6 02/11] perf tools: Decouple thread->address_space on libunwind
Currently, the type of thread->addr_space is unw_addr_space_t, which is a pointer defined in libunwind headers. For local libunwind, we can simple include "libunwind.h", but for remote libunwind, the header file is depends on the target libunwind platform. This patch uses 'void *' instead to decouple the dependence on libunwind. Signed-off-by: He Kuang --- tools/perf/util/thread.h | 5 + 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h index 45fba13..aa3a8ff 100644 --- a/tools/perf/util/thread.h +++ b/tools/perf/util/thread.h @@ -9,9 +9,6 @@ #include "symbol.h" #include #include -#ifdef HAVE_LIBUNWIND_SUPPORT -#include -#endif struct thread_stack; @@ -36,7 +33,7 @@ struct thread { void*priv; struct thread_stack *ts; #ifdef HAVE_LIBUNWIND_SUPPORT - unw_addr_space_taddr_space; + void*addr_space; #endif }; -- 1.8.5.2
[PATCH v6 10/11] perf callchain: Support x86 target platform
Support x86(32-bit) cross platform callchain unwind. Signed-off-by: He Kuang --- tools/perf/arch/Build | 1 + tools/perf/arch/x86/util/unwind-libunwind.c| 7 --- tools/perf/arch/x86/util/unwind-libunwind_x86_32.c | 21 + tools/perf/util/unwind-libunwind-local.c | 4 tools/perf/util/unwind-libunwind.c | 19 +-- tools/perf/util/unwind.h | 10 ++ 6 files changed, 53 insertions(+), 9 deletions(-) create mode 100644 tools/perf/arch/x86/util/unwind-libunwind_x86_32.c diff --git a/tools/perf/arch/Build b/tools/perf/arch/Build index 109eb75..3fc4af1 100644 --- a/tools/perf/arch/Build +++ b/tools/perf/arch/Build @@ -1,2 +1,3 @@ libperf-y += common.o libperf-y += $(ARCH)/ +libperf-$(CONFIG_LIBUNWIND_X86) += x86/util/unwind-libunwind_x86_32.o diff --git a/tools/perf/arch/x86/util/unwind-libunwind.c b/tools/perf/arch/x86/util/unwind-libunwind.c index db25e93..3b0be69 100644 --- a/tools/perf/arch/x86/util/unwind-libunwind.c +++ b/tools/perf/arch/x86/util/unwind-libunwind.c @@ -1,12 +1,13 @@ - +#ifndef REMOTE_UNWIND_LIBUNWIND #include #include #include "perf_regs.h" #include "../../util/unwind.h" #include "../../util/debug.h" +#endif #ifdef HAVE_ARCH_X86_64_SUPPORT -int libunwind__arch_reg_id(int regnum) +int LIBUNWIND__ARCH_REG_ID(int regnum) { int id; @@ -70,7 +71,7 @@ int libunwind__arch_reg_id(int regnum) return id; } #else -int libunwind__arch_reg_id(int regnum) +int LIBUNWIND__ARCH_REG_ID(int regnum) { int id; diff --git a/tools/perf/arch/x86/util/unwind-libunwind_x86_32.c b/tools/perf/arch/x86/util/unwind-libunwind_x86_32.c new file mode 100644 index 000..9d5359e --- /dev/null +++ b/tools/perf/arch/x86/util/unwind-libunwind_x86_32.c @@ -0,0 +1,21 @@ +#define REMOTE_UNWIND_LIBUNWIND + +#define LIBUNWIND__ARCH_REG_ID libunwind__x86_reg_id + +#include "unwind.h" +#include "debug.h" +#include "libunwind-x86.h" +#include <../../../../../arch/x86/include/uapi/asm/perf_regs.h> + +#undef HAVE_ARCH_X86_64_SUPPORT +#include "unwind-libunwind.c" + +#undef NO_LIBUNWIND_DEBUG_FRAME +#define NO_LIBUNWIND_DEBUG_FRAME +#include "util/unwind-libunwind-local.c" + +int register_x86_32_unwind_libunwind_ops(struct thread *thread) +{ + thread->unwind_libunwind_ops = &_unwind_libunwind_ops; + return 0; +} diff --git a/tools/perf/util/unwind-libunwind-local.c b/tools/perf/util/unwind-libunwind-local.c index b391e3e..849fec1 100644 --- a/tools/perf/util/unwind-libunwind-local.c +++ b/tools/perf/util/unwind-libunwind-local.c @@ -5,7 +5,9 @@ #include #include #include +#ifndef REMOTE_UNWIND_LIBUNWIND #include +#endif #include "callchain.h" #include "thread.h" #include "session.h" @@ -671,7 +673,9 @@ _unwind_libunwind_ops = { .get_entries= _unwind__get_entries, }; +#ifndef REMOTE_UNWIND_LIBUNWIND void register_local_unwind_libunwind_ops(struct thread *thread) { thread->unwind_libunwind_ops = &_unwind_libunwind_ops; } +#endif diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c index 037ee72..c1d9d36 100644 --- a/tools/perf/util/unwind-libunwind.c +++ b/tools/perf/util/unwind-libunwind.c @@ -8,6 +8,9 @@ int unwind__prepare_access(struct thread *thread, struct map *map) { const char *arch; enum dso_type dso_type; + int use_local_unwind = 1; + int ret; + int (*register_func)(struct thread *thread) = NULL; if (!thread->mg->machine->env) return -1; @@ -22,16 +25,20 @@ int unwind__prepare_access(struct thread *thread, struct map *map) arch = normalize_arch(thread->mg->machine->env->arch); - if (!strcmp(arch, "x86")) { + if (!strcmp(arch, "x86")) if (dso_type != DSO__TYPE_64BIT) -#ifdef HAVE_LIBUNWIND_X86_SUPPORT - pr_err("unwind: target platform=%s is not implemented\n", arch); -#else + register_func = register_x86_32_unwind_libunwind_ops; + + if (register_func) { + ret = register_func(thread); + if (!ret) + use_local_unwind = 0; + else pr_err("unwind: target platform=%s is not supported\n", arch); -#endif } - register_local_unwind_libunwind_ops(thread); + if (use_local_unwind) + register_local_unwind_libunwind_ops(thread); return thread->unwind_libunwind_ops->prepare_access(thread); } diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h index 9e4f545..43f9f66 100644 --- a/tools/perf/util/unwind.h +++ b/tools/perf/util/unwind.h @@ -46,6 +46,16 @@ static inline void regis
[PATCH v6 01/11] perf tools: Use LIBUNWIND_DIR for remote libunwind feature check
Pass LIBUNWIND_DIR to feature check flags for remote libunwind tests. So perf can be able to detect remote libunwind libraries from arbitrary directory. Signed-off-by: He Kuang --- tools/perf/config/Makefile | 9 + 1 file changed, 9 insertions(+) diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index 1e46277..6f9f566 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile @@ -67,9 +67,18 @@ endif # # make DEBUG=1 LIBUNWIND_DIR=/opt/libunwind/ # + +libunwind_arch_set_flags = $(eval $(libunwind_arch_set_flags_code)) +define libunwind_arch_set_flags_code + FEATURE_CHECK_CFLAGS-libunwind-$(1) = -I$(LIBUNWIND_DIR)/include + FEATURE_CHECK_LDFLAGS-libunwind-$(1) = -L$(LIBUNWIND_DIR)/lib +endef + ifdef LIBUNWIND_DIR LIBUNWIND_CFLAGS = -I$(LIBUNWIND_DIR)/include LIBUNWIND_LDFLAGS = -L$(LIBUNWIND_DIR)/lib + LIBUNWIND_ARCHS = x86 x86_64 arm aarch64 debug-frame-arm debug-frame-aarch64 + $(foreach libunwind_arch,$(LIBUNWIND_ARCHS),$(call libunwind_arch_set_flags,$(libunwind_arch))) endif LIBUNWIND_LDFLAGS += $(LIBUNWIND_LIBS) -- 1.8.5.2
[PATCH v6 09/11] perf tools: Change fixed name of libunwind__arch_reg_id to macro
For local libunwind, it uses the fixed methods to convert register id according to the host platform, but in remote libunwind, this convert function should be the one for remote architechture. This patch changes the fixed name to macro and code for each remote platform can be compiled indivadually. Signed-off-by: He Kuang --- tools/perf/util/unwind-libunwind-local.c | 2 +- tools/perf/util/unwind.h | 5 - 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/unwind-libunwind-local.c b/tools/perf/util/unwind-libunwind-local.c index 5599adc..b391e3e 100644 --- a/tools/perf/util/unwind-libunwind-local.c +++ b/tools/perf/util/unwind-libunwind-local.c @@ -490,7 +490,7 @@ static int access_reg(unw_addr_space_t __maybe_unused as, return 0; } - id = libunwind__arch_reg_id(regnum); + id = LIBUNWIND__ARCH_REG_ID(regnum); if (id < 0) return -EINVAL; diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h index 4de423c..9e4f545 100644 --- a/tools/perf/util/unwind.h +++ b/tools/perf/util/unwind.h @@ -21,7 +21,10 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg, /* libunwind specific */ #ifdef HAVE_LIBUNWIND_SUPPORT -int libunwind__arch_reg_id(int regnum); +#ifndef LIBUNWIND__ARCH_REG_ID +#define LIBUNWIND__ARCH_REG_ID libunwind__arch_reg_id +#endif +int LIBUNWIND__ARCH_REG_ID(int regnum); int unwind__prepare_access(struct thread *thread, struct map *map); void unwind__flush_access(struct thread *thread); void unwind__finish_access(struct thread *thread); -- 1.8.5.2
[PATCH v6 05/11] perf tools: Separate local/remote libunwind config
CONFIG_LIBUNWIND/NO_LIBUNWIND are changed to CONFIG_LOCAL_LIBUNWIND/NO_LOCAL_LIBUNWIND for retaining local unwind features. The new CONFIG_LIBUNWIND stands for either local or remote or both unwind are supported. Signed-off-by: He Kuang --- tools/perf/arch/arm/util/Build | 2 +- tools/perf/arch/arm64/util/Build | 2 +- tools/perf/arch/x86/util/Build | 2 +- tools/perf/config/Makefile | 21 +++-- tools/perf/util/unwind.h | 8 +++- 5 files changed, 29 insertions(+), 6 deletions(-) diff --git a/tools/perf/arch/arm/util/Build b/tools/perf/arch/arm/util/Build index d22e3d0..52d0ff8 100644 --- a/tools/perf/arch/arm/util/Build +++ b/tools/perf/arch/arm/util/Build @@ -1,4 +1,4 @@ libperf-$(CONFIG_DWARF) += dwarf-regs.o -libperf-$(CONFIG_LIBUNWIND) += unwind-libunwind.o +libperf-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o diff --git a/tools/perf/arch/arm64/util/Build b/tools/perf/arch/arm64/util/Build index e58123a8..02f41db 100644 --- a/tools/perf/arch/arm64/util/Build +++ b/tools/perf/arch/arm64/util/Build @@ -1,2 +1,2 @@ libperf-$(CONFIG_DWARF) += dwarf-regs.o -libperf-$(CONFIG_LIBUNWIND) += unwind-libunwind.o +libperf-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o diff --git a/tools/perf/arch/x86/util/Build b/tools/perf/arch/x86/util/Build index 4659703..1db8abd 100644 --- a/tools/perf/arch/x86/util/Build +++ b/tools/perf/arch/x86/util/Build @@ -7,7 +7,7 @@ libperf-y += perf_regs.o libperf-$(CONFIG_DWARF) += dwarf-regs.o libperf-$(CONFIG_BPF_PROLOGUE) += dwarf-regs.o -libperf-$(CONFIG_LIBUNWIND) += unwind-libunwind.o +libperf-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o libperf-$(CONFIG_AUXTRACE) += auxtrace.o diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index 6f9f566..3a304a3 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile @@ -354,10 +354,24 @@ ifeq ($(ARCH),powerpc) endif ifndef NO_LIBUNWIND + have_libunwind := ifneq ($(feature-libunwind), 1) msg := $(warning No libunwind found. Please install libunwind-dev[el] >= 1.1 and/or set LIBUNWIND_DIR); +NO_LOCAL_LIBUNWIND := 1 + else +have_libunwind := 1 +CFLAGS += -DHAVE_LIBUNWIND_LOCAL_SUPPORT +$(call detected,CONFIG_LOCAL_LIBUNWIND) + endif + + ifneq ($(have_libunwind), 1) NO_LIBUNWIND := 1 + else +CFLAGS += -I$(LIBUNWIND_DIR)/include +LDFLAGS += -L$(LIBUNWIND_DIR)/lib endif +else + NO_LOCAL_LIBUNWIND := 1 endif ifndef NO_LIBBPF @@ -395,7 +409,7 @@ else NO_DWARF_UNWIND := 1 endif -ifndef NO_LIBUNWIND +ifndef NO_LOCAL_LIBUNWIND ifeq ($(ARCH),$(filter $(ARCH),arm arm64)) $(call feature_check,libunwind-debug-frame) ifneq ($(feature-libunwind-debug-frame), 1) @@ -406,12 +420,15 @@ ifndef NO_LIBUNWIND # non-ARM has no dwarf_find_debug_frame() function: CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME endif - CFLAGS += -DHAVE_LIBUNWIND_SUPPORT EXTLIBS += $(LIBUNWIND_LIBS) CFLAGS += $(LIBUNWIND_CFLAGS) LDFLAGS += $(LIBUNWIND_LDFLAGS) endif +ifndef NO_LIBUNWIND + CFLAGS += -DHAVE_LIBUNWIND_SUPPORT +endif + ifndef NO_LIBAUDIT ifneq ($(feature-libaudit), 1) msg := $(warning No libaudit.h found, disables 'trace' tool, please install audit-libs-devel or libaudit-dev); diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h index 5f36415..0122797 100644 --- a/tools/perf/util/unwind.h +++ b/tools/perf/util/unwind.h @@ -18,13 +18,13 @@ typedef int (*unwind_entry_cb_t)(struct unwind_entry *entry, void *arg); int unwind__get_entries(unwind_entry_cb_t cb, void *arg, struct thread *thread, struct perf_sample *data, int max_stack); + /* libunwind specific */ #ifdef HAVE_LIBUNWIND_SUPPORT int libunwind__arch_reg_id(int regnum); int unwind__prepare_access(struct thread *thread); void unwind__flush_access(struct thread *thread); void unwind__finish_access(struct thread *thread); -void register_local_unwind_libunwind_ops(struct thread *thread); #else static inline int unwind__prepare_access(struct thread *thread __maybe_unused) { @@ -33,9 +33,15 @@ static inline int unwind__prepare_access(struct thread *thread __maybe_unused) static inline void unwind__flush_access(struct thread *thread __maybe_unused) {} static inline void unwind__finish_access(struct thread *thread __maybe_unused) {} +#endif + +#ifdef HAVE_LIBUNWIND_LOCAL_SUPPORT +void register_local_unwind_libunwind_ops(struct thread *thread); +#else static inline void register_local_unwind_libunwind_ops(struct thread *thread __maybe_unused) {} #endif + #else static inline int unwind__get_entries(unwind_entry_cb_t cb __maybe_unused, -- 1.8.5.2
[PATCH v6 00/11] Add support for remote unwind
v5 url: http://thread.gmane.org/gmane.linux.kernel/2226821 Currently, perf script uses host unwind methods(local unwind) to parse perf.data callchain info regardless of the target architecture. So we get wrong result and no promotion when do remote unwind on other platforms/machines. This patchset checks whether a dso is 32-bit or 64-bit according to elf class info for each thread to let perf use the correct remote unwind methods instead. Only x86 and aarch64 is added in this patchset to show the work flow, other platforms can be added easily. We can see the right result for unwind info on different machines, for example: perf.data recorded on i686 qemu with '-g' option and parsed on x86_64 machine. before this patchset: hello 1219 [001] 72190.667975: probe:sys_close: (c1169d60) c1169d61 sys_close ([kernel.kallsyms]) c189c0d7 sysenter_past_esp ([kernel.kallsyms]) b777aba9 [unknown] ([vdso32]) after: (Add vdso into buildid-cache first by 'perf buildid-cache -a' and libraries are provided in symfs dir) hello 1219 [001] 72190.667975: probe:sys_close: (c1169d60) c1169d61 sys_close ([kernel.kallsyms]) c189c0d7 sysenter_past_esp ([kernel.kallsyms]) b777aba9 __kernel_vsyscall ([vdso32]) b76971cc close (/lib/libc-2.22.so) 804842e fib (/tmp/hello) 804849d main (/tmp/hello) b75d746e __libc_start_main (/lib/libc-2.22.so) 8048341 _start (/tmp/hello) For using remote libunwind libraries, reference this: http://thread.gmane.org/gmane.linux.kernel/2224430 and now we can use LIBUNWIND_DIR to specific custom dirctories containing libunwind libs. v6: By following the advises from Jiri Olsa: - Introducing struct unwind_libunwind_ops for local unwind - Move unwind__prepare_access from thread_new into thread__insert_map - Extract local libunwind code out of unwind-libunwind.c - Other changes mentioned in v5 mails. Thanks. He Kuang (11): perf tools: Use LIBUNWIND_DIR for remote libunwind feature check perf tools: Decouple thread->address_space on libunwind perf tools: Introducing struct unwind_libunwind_ops for local unwind perf tools: Move unwind__prepare_access from thread_new into thread__insert_map perf tools: Separate local/remote libunwind config perf tools: Extract local libunwind code out of unwind-libunwind.c perf tools: Export normalize_arch() function perf tools: Show warnings for unsupported cross-platform unwind perf tools: Change fixed name of libunwind__arch_reg_id to macro perf callchain: Support x86 target platform perf callchain: Support aarch64 cross-platform tools/perf/arch/Build | 2 + tools/perf/arch/arm/util/Build | 2 +- tools/perf/arch/arm64/util/Build | 2 +- tools/perf/arch/arm64/util/unwind-libunwind.c | 4 +- .../perf/arch/arm64/util/unwind-libunwind_arm64.c | 22 + tools/perf/arch/common.c | 2 +- tools/perf/arch/common.h | 1 + tools/perf/arch/x86/util/Build | 2 +- tools/perf/arch/x86/util/unwind-libunwind.c| 7 +- tools/perf/arch/x86/util/unwind-libunwind_x86_32.c | 21 + tools/perf/config/Makefile | 50 +- tools/perf/util/Build | 1 + tools/perf/util/thread.c | 5 +- tools/perf/util/thread.h | 17 +- tools/perf/util/unwind-libunwind-local.c | 681 tools/perf/util/unwind-libunwind.c | 697 ++--- tools/perf/util/unwind.h | 41 +- 17 files changed, 884 insertions(+), 673 deletions(-) create mode 100644 tools/perf/arch/arm64/util/unwind-libunwind_arm64.c create mode 100644 tools/perf/arch/x86/util/unwind-libunwind_x86_32.c create mode 100644 tools/perf/util/unwind-libunwind-local.c -- 1.8.5.2
[PATCH v6 03/11] perf tools: Introducing struct unwind_libunwind_ops for local unwind
Currently, libunwind operations are fixed, and they are chosen according to the host architecture. This will lead a problem that if a thread is run as x86_32 on x86_64 machine, perf will use libunwind methods for x86_64 to parse the callchain and get wrong result. This patch changes the fixed methods of libunwind operations to thread/map related, and each thread can have indivadual libunwind operations. Local libunwind methods are registered as default value. Signed-off-by: He Kuang --- tools/perf/util/thread.c | 2 ++ tools/perf/util/thread.h | 14 +- tools/perf/util/unwind-libunwind.c | 55 ++ tools/perf/util/unwind.h | 5 4 files changed, 70 insertions(+), 6 deletions(-) diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 45fcb71..6d3900c 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c @@ -43,6 +43,8 @@ struct thread *thread__new(pid_t pid, pid_t tid) thread->cpu = -1; INIT_LIST_HEAD(&thread->comm_list); + register_local_unwind_libunwind_ops(thread); + if (unwind__prepare_access(thread) < 0) goto err_thread; diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h index aa3a8ff..647b011 100644 --- a/tools/perf/util/thread.h +++ b/tools/perf/util/thread.h @@ -12,6 +12,17 @@ struct thread_stack; +struct unwind_entry; +typedef int (*unwind_entry_cb_t)(struct unwind_entry *entry, void *arg); +struct unwind_libunwind_ops { + int (*prepare_access)(struct thread *thread); + void (*flush_access)(struct thread *thread); + void (*finish_access)(struct thread *thread); + int (*get_entries)(unwind_entry_cb_t cb, void *arg, + struct thread *thread, + struct perf_sample *data, int max_stack); +}; + struct thread { union { struct rb_node rb_node; @@ -33,7 +44,8 @@ struct thread { void*priv; struct thread_stack *ts; #ifdef HAVE_LIBUNWIND_SUPPORT - void*addr_space; + void*addr_space; + struct unwind_libunwind_ops *unwind_libunwind_ops; #endif }; diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c index 63687d3..0277b22 100644 --- a/tools/perf/util/unwind-libunwind.c +++ b/tools/perf/util/unwind-libunwind.c @@ -23,7 +23,6 @@ #include #include #include -#include #include "callchain.h" #include "thread.h" #include "session.h" @@ -579,7 +578,7 @@ static unw_accessors_t accessors = { .get_proc_name = get_proc_name, }; -int unwind__prepare_access(struct thread *thread) +static int _unwind__prepare_access(struct thread *thread) { if (callchain_param.record_mode != CALLCHAIN_DWARF) return 0; @@ -594,7 +593,7 @@ int unwind__prepare_access(struct thread *thread) return 0; } -void unwind__flush_access(struct thread *thread) +static void _unwind__flush_access(struct thread *thread) { if (callchain_param.record_mode != CALLCHAIN_DWARF) return; @@ -602,7 +601,7 @@ void unwind__flush_access(struct thread *thread) unw_flush_cache(thread->addr_space, 0, 0); } -void unwind__finish_access(struct thread *thread) +static void _unwind__finish_access(struct thread *thread) { if (callchain_param.record_mode != CALLCHAIN_DWARF) return; @@ -662,7 +661,7 @@ static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb, return ret; } -int unwind__get_entries(unwind_entry_cb_t cb, void *arg, +static int _unwind__get_entries(unwind_entry_cb_t cb, void *arg, struct thread *thread, struct perf_sample *data, int max_stack) { @@ -680,3 +679,49 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg, return get_entries(&ui, cb, arg, max_stack); } + +static struct unwind_libunwind_ops +_unwind_libunwind_ops = { + .prepare_access = _unwind__prepare_access, + .flush_access = _unwind__flush_access, + .finish_access = _unwind__finish_access, + .get_entries= _unwind__get_entries, +}; + +void register_local_unwind_libunwind_ops(struct thread *thread) +{ + thread->unwind_libunwind_ops = &_unwind_libunwind_ops; +} + +int unwind__prepare_access(struct thread *thread) +{ + if (thread->unwind_libunwind_ops) + return thread->unwind_libunwind_ops->prepare_access(thread); + else + return 0; +} + +void unwind__flush_access(struct thread *thread) +{ + if (thread->unwind_libunwind_ops) + thread->unwind_libunwind_ops->flush_access(thread); +} + +void unwind__finish_access(struct thread *thread) +{ + if (thread->unw
[PATCH v6 08/11] perf tools: Show warnings for unsupported cross-platform unwind
Currently, perf script uses host unwind methods to parse perf.data callchain info regardless of the target architecture. So we get wrong result without any warnings when unwinding callchains of x86(32-bit) on x86(64-bit) machine. This patch shows warning messages when we do remote unwind x86(32-bit) on other machines. Same thing for other platforms will be added in next patches. Signed-off-by: He Kuang --- tools/perf/config/Makefile | 8 tools/perf/util/thread.c | 2 +- tools/perf/util/unwind-libunwind.c | 30 +- tools/perf/util/unwind.h | 5 +++-- 4 files changed, 41 insertions(+), 4 deletions(-) diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index 3a304a3..e156f76 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile @@ -355,6 +355,14 @@ endif ifndef NO_LIBUNWIND have_libunwind := + + ifeq ($(feature-libunwind-x86), 1) +$(call detected,CONFIG_LIBUNWIND_X86) +CFLAGS += -DHAVE_LIBUNWIND_X86_SUPPORT +LDFLAGS += -lunwind-x86 +have_libunwind = 1 + endif + ifneq ($(feature-libunwind), 1) msg := $(warning No libunwind found. Please install libunwind-dev[el] >= 1.1 and/or set LIBUNWIND_DIR); NO_LOCAL_LIBUNWIND := 1 diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 045477d..7ffee25 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c @@ -203,7 +203,7 @@ void thread__insert_map(struct thread *thread, struct map *map) map_groups__fixup_overlappings(thread->mg, map, stderr); map_groups__insert(thread->mg, map); - unwind__prepare_access(thread); + unwind__prepare_access(thread, map); } static int thread__clone_map_groups(struct thread *thread, diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c index 40d0453..037ee72 100644 --- a/tools/perf/util/unwind-libunwind.c +++ b/tools/perf/util/unwind-libunwind.c @@ -1,8 +1,36 @@ #include "unwind.h" #include "thread.h" +#include "session.h" +#include "debug.h" +#include "arch/common.h" -int unwind__prepare_access(struct thread *thread) +int unwind__prepare_access(struct thread *thread, struct map *map) { + const char *arch; + enum dso_type dso_type; + + if (!thread->mg->machine->env) + return -1; + + dso_type = dso__type(map->dso, thread->mg->machine); + if (dso_type == DSO__TYPE_UNKNOWN) + return -1; + + if (thread->addr_space) + pr_debug("unwind: thread map already set, 64bit is %d, dso=%s\n", +dso_type == DSO__TYPE_64BIT, map->dso->name); + + arch = normalize_arch(thread->mg->machine->env->arch); + + if (!strcmp(arch, "x86")) { + if (dso_type != DSO__TYPE_64BIT) +#ifdef HAVE_LIBUNWIND_X86_SUPPORT + pr_err("unwind: target platform=%s is not implemented\n", arch); +#else + pr_err("unwind: target platform=%s is not supported\n", arch); +#endif + } + register_local_unwind_libunwind_ops(thread); return thread->unwind_libunwind_ops->prepare_access(thread); diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h index 0122797..4de423c 100644 --- a/tools/perf/util/unwind.h +++ b/tools/perf/util/unwind.h @@ -22,11 +22,12 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg, /* libunwind specific */ #ifdef HAVE_LIBUNWIND_SUPPORT int libunwind__arch_reg_id(int regnum); -int unwind__prepare_access(struct thread *thread); +int unwind__prepare_access(struct thread *thread, struct map *map); void unwind__flush_access(struct thread *thread); void unwind__finish_access(struct thread *thread); #else -static inline int unwind__prepare_access(struct thread *thread __maybe_unused) +static inline int unwind__prepare_access(struct thread *thread __maybe_unused, +struct map *map __maybe_unused) { return 0; } -- 1.8.5.2
[PATCH v3 1/7 UPDATE] perf tools: Find vdso with the consider of cross-platform
There's a problem in machine__findnew_vdso(), vdso buildid generated by a 32-bit machine stores it with the name 'vdso', but when processing buildid on a 64-bit machine with the same 'perf.data', perf will search for vdso named as 'vdso32' and get failed. This patch tries to find the exsiting dsos in machine->dsos by thread dso_type. 64-bit thread tries to find vdso with name 'vdso', because all 64-bit vdso is named as that. 32-bit thread first tries to find vdso with name 'vdso32' if this thread was run on 64-bit machine, if failed, then it tries 'vdso' which indicates that the thread was run on 32-bit machine when recording. Signed-off-by: He Kuang --- tools/perf/util/vdso.c | 40 +--- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/tools/perf/util/vdso.c b/tools/perf/util/vdso.c index 44d440d..99f4a3d 100644 --- a/tools/perf/util/vdso.c +++ b/tools/perf/util/vdso.c @@ -134,8 +134,6 @@ static struct dso *__machine__addnew_vdso(struct machine *machine, const char *s return dso; } -#if BITS_PER_LONG == 64 - static enum dso_type machine__thread_dso_type(struct machine *machine, struct thread *thread) { @@ -156,6 +154,8 @@ static enum dso_type machine__thread_dso_type(struct machine *machine, return dso_type; } +#if BITS_PER_LONG == 64 + static int vdso__do_copy_compat(FILE *f, int fd) { char buf[4096]; @@ -283,8 +283,38 @@ static int __machine__findnew_vdso_compat(struct machine *machine, #endif +static struct dso *machine__find_vdso(struct machine *machine, + struct thread *thread) +{ + struct dso *dso = NULL; + enum dso_type dso_type; + + dso_type = machine__thread_dso_type(machine, thread); + switch (dso_type) { + case DSO__TYPE_32BIT: + dso = __dsos__find(&machine->dsos, DSO__NAME_VDSO32, true); + if (!dso) + dso = __dsos__find(&machine->dsos, DSO__NAME_VDSO, + true); + break; + case DSO__TYPE_X32BIT: + dso = __dsos__find(&machine->dsos, DSO__NAME_VDSOX32, true); + if (!dso) + dso = __dsos__find(&machine->dsos, DSO__NAME_VDSO, + true); + break; + case DSO__TYPE_64BIT: + case DSO__TYPE_UNKNOWN: + default: + dso = __dsos__find(&machine->dsos, DSO__NAME_VDSO, true); + break; + } + + return dso; +} + struct dso *machine__findnew_vdso(struct machine *machine, - struct thread *thread __maybe_unused) + struct thread *thread) { struct vdso_info *vdso_info; struct dso *dso = NULL; @@ -297,6 +327,10 @@ struct dso *machine__findnew_vdso(struct machine *machine, if (!vdso_info) goto out_unlock; + dso = machine__find_vdso(machine, thread); + if (dso) + goto out_unlock; + #if BITS_PER_LONG == 64 if (__machine__findnew_vdso_compat(machine, thread, vdso_info, &dso)) goto out_unlock; -- 1.8.5.2
[PATCH v3 3/7 UPDATE] perf tools: Add option for the path of buildid dsos under symfs
In the cross-platform perf record/script scenario, we need vdsos in buildid-cache dir and other libs in symfs dir at the same time. For the reason that to have every single file opened by perf is relative to symfs dirctory, perf skips the buildid dir if symfs is given. This patch references the buildid dir under symfs if '--symfs' is used, and adds new option '--dso-prefix' to specify the subdir path in symfs which contains the buildid dsos. Signed-off-by: He Kuang --- tools/perf/builtin-script.c | 2 ++ tools/perf/util/config.c| 10 ++ tools/perf/util/dso.c | 6 -- tools/perf/util/symbol.c| 1 + tools/perf/util/symbol.h| 1 + tools/perf/util/util.h | 1 + 6 files changed, 19 insertions(+), 2 deletions(-) diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 8f6ab2a..52526e8 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -2043,6 +2043,8 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) "Enable symbol demangling"), OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel, "Enable kernel symbol demangling"), + OPT_STRING(0, "dso-prefix", &symbol_conf.dso_prefix, "direcotry", + "Look for dsos relative to this directory under symfs"), OPT_END() }; diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c index 664490b..17bee62 100644 --- a/tools/perf/util/config.c +++ b/tools/perf/util/config.c @@ -553,3 +553,13 @@ void set_buildid_dir(const char *dir) /* for communicating with external commands */ setenv("PERF_BUILDID_DIR", buildid_dir, 1); } + +static bool buildid_dir_under_symfs_flag; +void set_buildid_dir_under_symfs(void) +{ + if (!buildid_dir_under_symfs_flag && symbol_conf.symfs[0]) { + __symbol__join_symfs(buildid_dir, MAXPATHLEN-1, +symbol_conf.dso_prefix); + buildid_dir_under_symfs_flag = true; + } +} diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c index b39b80c..fb34274 100644 --- a/tools/perf/util/dso.c +++ b/tools/perf/util/dso.c @@ -64,8 +64,10 @@ int dso__read_binary_type_filename(const struct dso *dso, 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, filename, size) == NULL)) + if (symbol_conf.symfs[0]) + set_buildid_dir_under_symfs(); + + if (dso__build_id_filename(dso, filename, size) == NULL) ret = -1; break; diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index e7588dc..7aa34ca 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -40,6 +40,7 @@ struct symbol_conf symbol_conf = { .show_hist_headers = true, .symfs = "", .event_group= true, + .dso_prefix = "", }; static enum dso_binary_type binary_type_symtab[] = { diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index c8b7544..c0fefdb 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -136,6 +136,7 @@ struct symbol_conf { struct intlist *pid_list, *tid_list; const char *symfs; + const char *dso_prefix; }; extern struct symbol_conf symbol_conf; diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 3bf3de8..f8e5582 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -142,6 +142,7 @@ void set_warning_routine(void (*routine)(const char *err, va_list params)); int prefixcmp(const char *str, const char *prefix); void set_buildid_dir(const char *dir); +void set_buildid_dir_under_symfs(void); #ifdef __GLIBC_PREREQ #if __GLIBC_PREREQ(2, 1) -- 1.8.5.2
[PATCH] perf script: Fix display inconsitency when call-graph config is used
There's a display inconsistency when 'call-graph' config event appears in different position. The problem can be reproduced like this: We record signal_deliver with call-graph and signal_generate without it. $ perf record -g -a -e signal:signal_deliver -e signal:signal_generate/call-graph=no/ [ perf record: Captured and wrote 0.017 MB perf.data (2 samples) ] $ perf script kworker/u2:113 [000] 6563.875949: signal:signal_generate: sig=2 errno=0 code=128 comm=perf pid=1313 grp=1 res=0 ff61cc __send_signal+0x3ec ([kernel.kallsyms]) perf 1313 [000] 6563.877584: signal:signal_deliver: sig=2 errno=0 code=128 sa_handler=43115e sa_flags=1400 7314 get_signal+0x80007f0023a4 ([kernel.kallsyms]) 7fffe358 do_signal+0x80007f002028 ([kernel.kallsyms]) 7fffa5e8 exit_to_usermode_loop+0x80007f002053 ([kernel.kallsyms]) ... Then we exchange the order of these two events in commandline, and keep signal_generate without call-graph. $ perf record -g -a -e signal:signal_generate/call-graph=no/ -e signal:signal_deliver [ perf record: Captured and wrote 0.017 MB perf.data (2 samples) ] $ perf script kworker/u2:2 1314 [000] 6933.353060: signal:signal_generate: sig=2 errno=0 code=128 comm=perf pid=1321 grp=1 res=0 perf 1321 [000] 6933.353872: signal:signal_deliver: sig=2 errno=0 code=128 sa_handler=43115e sa_flags=1400 This time, the callchain of the event signal_deliver disappeared. The problem is caused by that perf only checks for the first evsel in evlist and decides if callchain should be printed. This patch travseres all evsels in evlist to see if any of them have callchains, and shows the right result: $ perf script kworker/u2:2 1314 [000] 6933.353060: signal:signal_generate: sig=2 errno=0 code=128 comm=perf pid=1321 grp=1 res=0 ff61cc __send_signal+0x3ec ([kernel.kallsyms]) perf 1321 [000] 6933.353872: signal:signal_deliver: sig=2 errno=0 code=128 sa_handler=43115e sa_flags=1400 7314 get_signal+0x80007f0023a4 ([kernel.kallsyms]) 7fffe358 do_signal+0x80007f002028 ([kernel.kallsyms]) 7fffa5e8 exit_to_usermode_loop+0x80007f002053 ([kernel.kallsyms]) ... Signed-off-by: He Kuang --- tools/perf/builtin-script.c | 23 +-- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index efca816..7a18b92 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -339,7 +339,7 @@ static void set_print_ip_opts(struct perf_event_attr *attr) */ static int perf_session__check_output_opt(struct perf_session *session) { - int j; + unsigned int j; struct perf_evsel *evsel; for (j = 0; j < PERF_TYPE_MAX; ++j) { @@ -388,17 +388,20 @@ static int perf_session__check_output_opt(struct perf_session *session) struct perf_event_attr *attr; j = PERF_TYPE_TRACEPOINT; - evsel = perf_session__find_first_evtype(session, j); - if (evsel == NULL) - goto out; - attr = &evsel->attr; + evlist__for_each(session->evlist, evsel) { + if (evsel->attr.type != j) + continue; + + attr = &evsel->attr; - if (attr->sample_type & PERF_SAMPLE_CALLCHAIN) { - output[j].fields |= PERF_OUTPUT_IP; - output[j].fields |= PERF_OUTPUT_SYM; - output[j].fields |= PERF_OUTPUT_DSO; - set_print_ip_opts(attr); + if (attr->sample_type & PERF_SAMPLE_CALLCHAIN) { + output[j].fields |= PERF_OUTPUT_IP; + output[j].fields |= PERF_OUTPUT_SYM; + output[j].fields |= PERF_OUTPUT_DSO; + set_print_ip_opts(attr); + goto out; + } } } -- 1.8.5.2
[RFC PATCH v6 2/2] bpf: Introduce function for outputing data to perf event
There're scenarios that we need an eBPF program to record not only kprobe point args, but also the PMU counters, time latencies or the number of cache misses between two probe points and other information when the probe point is entered. This patch adds a new trace event to establish infrastruction for bpf to output data to perf. Userspace perf tools can detect and use this event as using the existing tracepoint events. New bpf trace event entry in debugfs: /sys/kernel/debug/tracing/events/bpf/bpf_output_data Userspace perf tools detect the new tracepoint event as: bpf:bpf_output_data [Tracepoint event] Data in ring-buffer of perf events added to this event will be polled out, sample types and other attributes can be adjusted to those events directly without touching the original kprobe events. The bpf helper function gives eBPF program ability to output data as perf sample event. This helper simple call the new trace event and userspace perf tools can record the BPF ftrace event to collect those records. Signed-off-by: He Kuang Acked-by: Alexei Starovoitov --- include/trace/events/bpf.h | 30 ++ include/uapi/linux/bpf.h | 7 +++ kernel/trace/bpf_trace.c | 23 +++ samples/bpf/bpf_helpers.h | 2 ++ 4 files changed, 62 insertions(+) create mode 100644 include/trace/events/bpf.h diff --git a/include/trace/events/bpf.h b/include/trace/events/bpf.h new file mode 100644 index 000..6b739b8 --- /dev/null +++ b/include/trace/events/bpf.h @@ -0,0 +1,30 @@ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM bpf + +#if !defined(_TRACE_BPF_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_BPF_H + +#include + +TRACE_EVENT(bpf_output_data, + + TP_PROTO(u64 *src, int size), + + TP_ARGS(src, size), + + TP_STRUCT__entry( + __dynamic_array(u8, buf,size) + ), + + TP_fast_assign( + memcpy(__get_dynamic_array(buf), src, size); + ), + + TP_printk("%s", __print_hex(__get_dynamic_array(buf), + __get_dynamic_array_len(buf))) +); + +#endif /* _TRACE_BPF_H */ + +/* This part must be outside protection */ +#include diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 29ef6f9..5068ab1 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -249,6 +249,13 @@ enum bpf_func_id { * Return: 0 on success */ BPF_FUNC_get_current_comm, + + /** +* int bpf_output_trace_data(void *src, int size) +* Return: 0 on success +*/ + BPF_FUNC_output_trace_data, + __BPF_FUNC_MAX_ID, }; diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c index 88a041a..219f670 100644 --- a/kernel/trace/bpf_trace.c +++ b/kernel/trace/bpf_trace.c @@ -11,7 +11,10 @@ #include #include #include + #include "trace.h" +#define CREATE_TRACE_POINTS +#include static DEFINE_PER_CPU(int, bpf_prog_active); @@ -79,6 +82,24 @@ static const struct bpf_func_proto bpf_probe_read_proto = { .arg3_type = ARG_ANYTHING, }; +static u64 bpf_output_trace_data(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5) +{ + void *src = (void *) (long) r1; + int size = (int) r2; + + trace_bpf_output_data(src, size); + + return 0; +} + +static const struct bpf_func_proto bpf_output_trace_data_proto = { + .func = bpf_output_trace_data, + .gpl_only = true, + .ret_type = RET_INTEGER, + .arg1_type = ARG_PTR_TO_STACK, + .arg2_type = ARG_CONST_STACK_SIZE, +}; + /* * limited trace_printk() * only %d %u %x %ld %lu %lx %lld %llu %llx %p conversion specifiers allowed @@ -169,6 +190,8 @@ static const struct bpf_func_proto *kprobe_prog_func_proto(enum bpf_func_id func return &bpf_map_delete_elem_proto; case BPF_FUNC_probe_read: return &bpf_probe_read_proto; + case BPF_FUNC_output_trace_data: + return &bpf_output_trace_data_proto; case BPF_FUNC_ktime_get_ns: return &bpf_ktime_get_ns_proto; case BPF_FUNC_tail_call: diff --git a/samples/bpf/bpf_helpers.h b/samples/bpf/bpf_helpers.h index bdf1c16..0aeaebe 100644 --- a/samples/bpf/bpf_helpers.h +++ b/samples/bpf/bpf_helpers.h @@ -59,5 +59,7 @@ static int (*bpf_l3_csum_replace)(void *ctx, int off, int from, int to, int flag (void *) BPF_FUNC_l3_csum_replace; static int (*bpf_l4_csum_replace)(void *ctx, int off, int from, int to, int flags) = (void *) BPF_FUNC_l4_csum_replace; +static int (*bpf_output_trace_data)(void *src, int size) = + (void *) BPF_FUNC_output_trace_data; #endif -- 1.8.5.2 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://
[RFC PATCH v6 1/2] tools lib traceevent: Support function __get_dynamic_array_len
Support helper function __get_dynamic_array_len() in libtraceevent, this function is used accompany with __print_array() or __print_hex(), but currently it is not an available function in the function list of process_function(). The total allocated length of the dynamic array is embedded in the top half of __data_loc_##item field. This patch adds new arg type PRINT_DYNAMIC_ARRAY_LEN to return the length to eval_num_arg(), Signed-off-by: He Kuang --- tools/lib/traceevent/event-parse.c | 56 +- tools/lib/traceevent/event-parse.h | 1 + .../perf/util/scripting-engines/trace-event-perl.c | 1 + .../util/scripting-engines/trace-event-python.c| 1 + 4 files changed, 57 insertions(+), 2 deletions(-) diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c index cc25f05..3af69cf 100644 --- a/tools/lib/traceevent/event-parse.c +++ b/tools/lib/traceevent/event-parse.c @@ -783,6 +783,7 @@ static void free_arg(struct print_arg *arg) free(arg->bitmask.bitmask); break; case PRINT_DYNAMIC_ARRAY: + case PRINT_DYNAMIC_ARRAY_LEN: free(arg->dynarray.index); break; case PRINT_OP: @@ -2655,6 +2656,42 @@ process_dynamic_array(struct event_format *event, struct print_arg *arg, char ** } static enum event_type +process_dynamic_array_len(struct event_format *event, struct print_arg *arg, + char **tok) +{ + struct format_field *field; + enum event_type type; + char *token; + + if (read_expect_type(EVENT_ITEM, &token) < 0) + goto out_free; + + arg->type = PRINT_DYNAMIC_ARRAY_LEN; + + /* Find the field */ + field = pevent_find_field(event, token); + if (!field) + goto out_free; + + arg->dynarray.field = field; + arg->dynarray.index = 0; + + if (read_expected(EVENT_DELIM, ")") < 0) + goto out_err; + + type = read_token(&token); + *tok = token; + + return type; + + out_free: + free_token(token); + out_err: + *tok = NULL; + return EVENT_ERROR; +} + +static enum event_type process_paren(struct event_format *event, struct print_arg *arg, char **tok) { struct print_arg *item_arg; @@ -2901,6 +2938,10 @@ process_function(struct event_format *event, struct print_arg *arg, free_token(token); return process_dynamic_array(event, arg, tok); } + if (strcmp(token, "__get_dynamic_array_len") == 0) { + free_token(token); + return process_dynamic_array_len(event, arg, tok); + } func = find_func_handler(event->pevent, token); if (func) { @@ -3581,14 +3622,25 @@ eval_num_arg(void *data, int size, struct event_format *event, struct print_arg goto out_warning_op; } break; + case PRINT_DYNAMIC_ARRAY_LEN: + offset = pevent_read_number(pevent, + data + arg->dynarray.field->offset, + arg->dynarray.field->size); + /* +* The total allocated length of the dynamic array is +* stored in the top half of the field, and the offset +* is in the bottom half of the 32 bit field. +*/ + val = (unsigned long long)(offset >> 16); + break; case PRINT_DYNAMIC_ARRAY: /* Without [], we pass the address to the dynamic data */ offset = pevent_read_number(pevent, data + arg->dynarray.field->offset, arg->dynarray.field->size); /* -* The actual length of the dynamic array is stored -* in the top half of the field, and the offset +* The total allocated length of the dynamic array is +* stored in the top half of the field, and the offset * is in the bottom half of the 32 bit field. */ offset &= 0x; diff --git a/tools/lib/traceevent/event-parse.h b/tools/lib/traceevent/event-parse.h index 063b197..94543aa 100644 --- a/tools/lib/traceevent/event-parse.h +++ b/tools/lib/traceevent/event-parse.h @@ -294,6 +294,7 @@ enum print_arg_type { PRINT_OP, PRINT_FUNC, PRINT_BITMASK, + PRINT_DYNAMIC_ARRAY_LEN, }; struct print_arg { diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c index 1bd593b..544509c 100644 --- a/tools/perf/util/scripting-engines/trace-event-perl.c +++ b/tools/perf/util/scripting-engines/trace-event-
[RFC PATCH v6 0/2] Make eBPF programs output data to perf
Hi, Previous patch v5 url: http://thread.gmane.org/gmane.linux.kernel/1995274 The bugfix of dynamic array length in trace event goes to kernel/git/rostedt/linux-trace.git ftrace/urgent and confirms that the return value of __get_dynamic_array_len() is the total allocated length of the dynamic array. For we print the bpf output data in byte array from patch v5, that problem does not affect our patch any more, but some comments in patch 1/2 is updated. Patch 2/2 is acked by Alexei. Thank you. He Kuang (2): tools lib traceevent: Support function __get_dynamic_array_len bpf: Introduce function for outputing data to perf event include/trace/events/bpf.h | 30 include/uapi/linux/bpf.h | 7 +++ kernel/trace/bpf_trace.c | 23 + samples/bpf/bpf_helpers.h | 2 + tools/lib/traceevent/event-parse.c | 56 +- tools/lib/traceevent/event-parse.h | 1 + .../perf/util/scripting-engines/trace-event-perl.c | 1 + .../util/scripting-engines/trace-event-python.c| 1 + 8 files changed, 119 insertions(+), 2 deletions(-) create mode 100644 include/trace/events/bpf.h -- 1.8.5.2 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/