Commit 45e6af06 authored by Ingo Molnar's avatar Ingo Molnar

Merge tag 'perf-core-for-mingo' of...

Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core

Pull perf improvements and fixes from Arnaldo Carvalho de Melo:

Infrastructure changes:

 * Improve callchain processing by removing unnecessary work. (Frederic Weisbecker)

 * Fix comm override error handling (Frederic Weisbecker)

 * Improve 'perf probe' exit path, release resources (Masami Hiramatsu)

 * Improve libtraceevent plugins exit path, allowing the registering of
   an unregister handler to be called at exit time (Namhyung Kim)

 * Add an alias to the build test makefile (make -C tools/perf build-test)
   (Namhyung Kim)
Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parents 3e7e09db 2a29190c
...@@ -5560,6 +5560,52 @@ int pevent_register_print_function(struct pevent *pevent, ...@@ -5560,6 +5560,52 @@ int pevent_register_print_function(struct pevent *pevent,
return ret; return ret;
} }
/**
* pevent_unregister_print_function - unregister a helper function
* @pevent: the handle to the pevent
* @func: the function to process the helper function
* @name: the name of the helper function
*
* This function removes existing print handler for function @name.
*
* Returns 0 if the handler was removed successully, -1 otherwise.
*/
int pevent_unregister_print_function(struct pevent *pevent,
pevent_func_handler func, char *name)
{
struct pevent_function_handler *func_handle;
func_handle = find_func_handler(pevent, name);
if (func_handle && func_handle->func == func) {
remove_func_handler(pevent, name);
return 0;
}
return -1;
}
static struct event_format *pevent_search_event(struct pevent *pevent, int id,
const char *sys_name,
const char *event_name)
{
struct event_format *event;
if (id >= 0) {
/* search by id */
event = pevent_find_event(pevent, id);
if (!event)
return NULL;
if (event_name && (strcmp(event_name, event->name) != 0))
return NULL;
if (sys_name && (strcmp(sys_name, event->system) != 0))
return NULL;
} else {
event = pevent_find_event_by_name(pevent, sys_name, event_name);
if (!event)
return NULL;
}
return event;
}
/** /**
* pevent_register_event_handler - register a way to parse an event * pevent_register_event_handler - register a way to parse an event
* @pevent: the handle to the pevent * @pevent: the handle to the pevent
...@@ -5584,20 +5630,9 @@ int pevent_register_event_handler(struct pevent *pevent, int id, ...@@ -5584,20 +5630,9 @@ int pevent_register_event_handler(struct pevent *pevent, int id,
struct event_format *event; struct event_format *event;
struct event_handler *handle; struct event_handler *handle;
if (id >= 0) { event = pevent_search_event(pevent, id, sys_name, event_name);
/* search by id */ if (event == NULL)
event = pevent_find_event(pevent, id); goto not_found;
if (!event)
goto not_found;
if (event_name && (strcmp(event_name, event->name) != 0))
goto not_found;
if (sys_name && (strcmp(sys_name, event->system) != 0))
goto not_found;
} else {
event = pevent_find_event_by_name(pevent, sys_name, event_name);
if (!event)
goto not_found;
}
pr_stat("overriding event (%d) %s:%s with new print handler", pr_stat("overriding event (%d) %s:%s with new print handler",
event->id, event->system, event->name); event->id, event->system, event->name);
...@@ -5637,6 +5672,79 @@ int pevent_register_event_handler(struct pevent *pevent, int id, ...@@ -5637,6 +5672,79 @@ int pevent_register_event_handler(struct pevent *pevent, int id,
return -1; return -1;
} }
static int handle_matches(struct event_handler *handler, int id,
const char *sys_name, const char *event_name,
pevent_event_handler_func func, void *context)
{
if (id >= 0 && id != handler->id)
return 0;
if (event_name && (strcmp(event_name, handler->event_name) != 0))
return 0;
if (sys_name && (strcmp(sys_name, handler->sys_name) != 0))
return 0;
if (func != handler->func || context != handler->context)
return 0;
return 1;
}
/**
* pevent_unregister_event_handler - unregister an existing event handler
* @pevent: the handle to the pevent
* @id: the id of the event to unregister
* @sys_name: the system name the handler belongs to
* @event_name: the name of the event handler
* @func: the function to call to parse the event information
* @context: the data to be passed to @func
*
* This function removes existing event handler (parser).
*
* If @id is >= 0, then it is used to find the event.
* else @sys_name and @event_name are used.
*
* Returns 0 if handler was removed successfully, -1 if event was not found.
*/
int pevent_unregister_event_handler(struct pevent *pevent, int id,
const char *sys_name, const char *event_name,
pevent_event_handler_func func, void *context)
{
struct event_format *event;
struct event_handler *handle;
struct event_handler **next;
event = pevent_search_event(pevent, id, sys_name, event_name);
if (event == NULL)
goto not_found;
if (event->handler == func && event->context == context) {
pr_stat("removing override handler for event (%d) %s:%s. Going back to default handler.",
event->id, event->system, event->name);
event->handler = NULL;
event->context = NULL;
return 0;
}
not_found:
for (next = &pevent->handlers; *next; next = &(*next)->next) {
handle = *next;
if (handle_matches(handle, id, sys_name, event_name,
func, context))
break;
}
if (!(*next))
return -1;
*next = handle->next;
free_handler(handle);
return 0;
}
/** /**
* pevent_alloc - create a pevent handle * pevent_alloc - create a pevent handle
*/ */
......
...@@ -624,10 +624,15 @@ int pevent_print_func_field(struct trace_seq *s, const char *fmt, ...@@ -624,10 +624,15 @@ int pevent_print_func_field(struct trace_seq *s, const char *fmt,
int pevent_register_event_handler(struct pevent *pevent, int id, int pevent_register_event_handler(struct pevent *pevent, int id,
const char *sys_name, const char *event_name, const char *sys_name, const char *event_name,
pevent_event_handler_func func, void *context); pevent_event_handler_func func, void *context);
int pevent_unregister_event_handler(struct pevent *pevent, int id,
const char *sys_name, const char *event_name,
pevent_event_handler_func func, void *context);
int pevent_register_print_function(struct pevent *pevent, int pevent_register_print_function(struct pevent *pevent,
pevent_func_handler func, pevent_func_handler func,
enum pevent_func_arg_type ret_type, enum pevent_func_arg_type ret_type,
char *name, ...); char *name, ...);
int pevent_unregister_print_function(struct pevent *pevent,
pevent_func_handler func, char *name);
struct format_field *pevent_find_common_field(struct event_format *event, const char *name); struct format_field *pevent_find_common_field(struct event_format *event, const char *name);
struct format_field *pevent_find_field(struct event_format *event, const char *name); struct format_field *pevent_find_field(struct event_format *event, const char *name);
......
...@@ -22,3 +22,9 @@ int PEVENT_PLUGIN_LOADER(struct pevent *pevent) ...@@ -22,3 +22,9 @@ int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
PEVENT_FUNC_ARG_VOID); PEVENT_FUNC_ARG_VOID);
return 0; return 0;
} }
void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent)
{
pevent_unregister_print_function(pevent, process___le16_to_cpup,
"__le16_to_cpup");
}
...@@ -148,6 +148,9 @@ void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent) ...@@ -148,6 +148,9 @@ void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent)
{ {
int i, x; int i, x;
pevent_unregister_event_handler(pevent, -1, "ftrace", "function",
function_handler, NULL);
for (i = 0; i <= cpus; i++) { for (i = 0; i <= cpus; i++) {
for (x = 0; x < fstack[i].size && fstack[i].stack[x]; x++) for (x = 0; x < fstack[i].size && fstack[i].stack[x]; x++)
free(fstack[i].stack[x]); free(fstack[i].stack[x]);
......
...@@ -76,3 +76,13 @@ int PEVENT_PLUGIN_LOADER(struct pevent *pevent) ...@@ -76,3 +76,13 @@ int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
timer_start_handler, NULL); timer_start_handler, NULL);
return 0; return 0;
} }
void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent)
{
pevent_unregister_event_handler(pevent, -1,
"timer", "hrtimer_expire_entry",
timer_expire_handler, NULL);
pevent_unregister_event_handler(pevent, -1, "timer", "hrtimer_start",
timer_start_handler, NULL);
}
...@@ -66,3 +66,12 @@ int PEVENT_PLUGIN_LOADER(struct pevent *pevent) ...@@ -66,3 +66,12 @@ int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
PEVENT_FUNC_ARG_VOID); PEVENT_FUNC_ARG_VOID);
return 0; return 0;
} }
void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent)
{
pevent_unregister_print_function(pevent, process_jbd2_dev_to_name,
"jbd2_dev_to_name");
pevent_unregister_print_function(pevent, process_jiffies_to_msecs,
"jiffies_to_msecs");
}
...@@ -70,3 +70,25 @@ int PEVENT_PLUGIN_LOADER(struct pevent *pevent) ...@@ -70,3 +70,25 @@ int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
call_site_handler, NULL); call_site_handler, NULL);
return 0; return 0;
} }
void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent)
{
pevent_unregister_event_handler(pevent, -1, "kmem", "kfree",
call_site_handler, NULL);
pevent_unregister_event_handler(pevent, -1, "kmem", "kmalloc",
call_site_handler, NULL);
pevent_unregister_event_handler(pevent, -1, "kmem", "kmalloc_node",
call_site_handler, NULL);
pevent_unregister_event_handler(pevent, -1, "kmem", "kmem_cache_alloc",
call_site_handler, NULL);
pevent_unregister_event_handler(pevent, -1, "kmem",
"kmem_cache_alloc_node",
call_site_handler, NULL);
pevent_unregister_event_handler(pevent, -1, "kmem", "kmem_cache_free",
call_site_handler, NULL);
}
...@@ -434,3 +434,32 @@ int PEVENT_PLUGIN_LOADER(struct pevent *pevent) ...@@ -434,3 +434,32 @@ int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
PEVENT_FUNC_ARG_VOID); PEVENT_FUNC_ARG_VOID);
return 0; return 0;
} }
void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent)
{
pevent_unregister_event_handler(pevent, -1, "kvm", "kvm_exit",
kvm_exit_handler, NULL);
pevent_unregister_event_handler(pevent, -1, "kvm", "kvm_emulate_insn",
kvm_emulate_insn_handler, NULL);
pevent_unregister_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_get_page",
kvm_mmu_get_page_handler, NULL);
pevent_unregister_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_sync_page",
kvm_mmu_print_role, NULL);
pevent_unregister_event_handler(pevent, -1,
"kvmmmu", "kvm_mmu_unsync_page",
kvm_mmu_print_role, NULL);
pevent_unregister_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_zap_page",
kvm_mmu_print_role, NULL);
pevent_unregister_event_handler(pevent, -1, "kvmmmu",
"kvm_mmu_prepare_zap_page", kvm_mmu_print_role,
NULL);
pevent_unregister_print_function(pevent, process_is_writable_pte,
"is_writable_pte");
}
...@@ -93,3 +93,10 @@ int PEVENT_PLUGIN_LOADER(struct pevent *pevent) ...@@ -93,3 +93,10 @@ int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
drv_bss_info_changed, NULL); drv_bss_info_changed, NULL);
return 0; return 0;
} }
void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent)
{
pevent_unregister_event_handler(pevent, -1, "mac80211",
"drv_bss_info_changed",
drv_bss_info_changed, NULL);
}
...@@ -146,3 +146,15 @@ int PEVENT_PLUGIN_LOADER(struct pevent *pevent) ...@@ -146,3 +146,15 @@ int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
sched_wakeup_handler, NULL); sched_wakeup_handler, NULL);
return 0; return 0;
} }
void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent)
{
pevent_unregister_event_handler(pevent, -1, "sched", "sched_switch",
sched_switch_handler, NULL);
pevent_unregister_event_handler(pevent, -1, "sched", "sched_wakeup",
sched_wakeup_handler, NULL);
pevent_unregister_event_handler(pevent, -1, "sched", "sched_wakeup_new",
sched_wakeup_handler, NULL);
}
...@@ -421,3 +421,9 @@ int PEVENT_PLUGIN_LOADER(struct pevent *pevent) ...@@ -421,3 +421,9 @@ int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
PEVENT_FUNC_ARG_VOID); PEVENT_FUNC_ARG_VOID);
return 0; return 0;
} }
void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent)
{
pevent_unregister_print_function(pevent, process_scsi_trace_parse_cdb,
"scsi_trace_parse_cdb");
}
...@@ -128,3 +128,9 @@ int PEVENT_PLUGIN_LOADER(struct pevent *pevent) ...@@ -128,3 +128,9 @@ int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
PEVENT_FUNC_ARG_VOID); PEVENT_FUNC_ARG_VOID);
return 0; return 0;
} }
void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent)
{
pevent_unregister_print_function(pevent, process_xen_hypercall_name,
"xen_hypercall_name");
}
...@@ -74,6 +74,12 @@ all tags TAGS: ...@@ -74,6 +74,12 @@ all tags TAGS:
clean: clean:
$(make) $(make)
#
# The build-test target is not really parallel, don't print the jobs info:
#
build-test:
@$(MAKE) -f tests/make --no-print-directory
# #
# All other targets get passed through: # All other targets get passed through:
# #
......
...@@ -59,7 +59,7 @@ static struct { ...@@ -59,7 +59,7 @@ static struct {
struct perf_probe_event events[MAX_PROBES]; struct perf_probe_event events[MAX_PROBES];
struct strlist *dellist; struct strlist *dellist;
struct line_range line_range; struct line_range line_range;
const char *target; char *target;
int max_probe_points; int max_probe_points;
struct strfilter *filter; struct strfilter *filter;
} params; } params;
...@@ -98,7 +98,10 @@ static int set_target(const char *ptr) ...@@ -98,7 +98,10 @@ static int set_target(const char *ptr)
* short module name. * short module name.
*/ */
if (!params.target && ptr && *ptr == '/') { if (!params.target && ptr && *ptr == '/') {
params.target = ptr; params.target = strdup(ptr);
if (!params.target)
return -ENOMEM;
found = 1; found = 1;
buf = ptr + (strlen(ptr) - 3); buf = ptr + (strlen(ptr) - 3);
...@@ -116,6 +119,9 @@ static int parse_probe_event_argv(int argc, const char **argv) ...@@ -116,6 +119,9 @@ static int parse_probe_event_argv(int argc, const char **argv)
char *buf; char *buf;
found_target = set_target(argv[0]); found_target = set_target(argv[0]);
if (found_target < 0)
return found_target;
if (found_target && argc == 1) if (found_target && argc == 1)
return 0; return 0;
...@@ -217,7 +223,6 @@ static int opt_show_lines(const struct option *opt __maybe_unused, ...@@ -217,7 +223,6 @@ static int opt_show_lines(const struct option *opt __maybe_unused,
params.show_lines = true; params.show_lines = true;
ret = parse_line_range_desc(str, &params.line_range); ret = parse_line_range_desc(str, &params.line_range);
INIT_LIST_HEAD(&params.line_range.line_list);
return ret; return ret;
} }
...@@ -263,7 +268,28 @@ static int opt_set_filter(const struct option *opt __maybe_unused, ...@@ -263,7 +268,28 @@ static int opt_set_filter(const struct option *opt __maybe_unused,
return 0; return 0;
} }
int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) static void init_params(void)
{
line_range__init(&params.line_range);
}
static void cleanup_params(void)
{
int i;
for (i = 0; i < params.nevents; i++)
clear_perf_probe_event(params.events + i);
if (params.dellist)
strlist__delete(params.dellist);
line_range__clear(&params.line_range);
free(params.target);
if (params.filter)
strfilter__delete(params.filter);
memset(&params, 0, sizeof(params));
}
static int
__cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
{ {
const char * const probe_usage[] = { const char * const probe_usage[] = {
"perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]", "perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]",
...@@ -417,6 +443,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -417,6 +443,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
ret = show_available_funcs(params.target, params.filter, ret = show_available_funcs(params.target, params.filter,
params.uprobes); params.uprobes);
strfilter__delete(params.filter); strfilter__delete(params.filter);
params.filter = NULL;
if (ret < 0) if (ret < 0)
pr_err(" Error: Failed to show functions." pr_err(" Error: Failed to show functions."
" (%d)\n", ret); " (%d)\n", ret);
...@@ -456,6 +483,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -456,6 +483,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
params.filter, params.filter,
params.show_ext_vars); params.show_ext_vars);
strfilter__delete(params.filter); strfilter__delete(params.filter);
params.filter = NULL;
if (ret < 0) if (ret < 0)
pr_err(" Error: Failed to show vars. (%d)\n", ret); pr_err(" Error: Failed to show vars. (%d)\n", ret);
return ret; return ret;
...@@ -464,7 +492,6 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -464,7 +492,6 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
if (params.dellist) { if (params.dellist) {
ret = del_perf_probe_events(params.dellist); ret = del_perf_probe_events(params.dellist);
strlist__delete(params.dellist);
if (ret < 0) { if (ret < 0) {
pr_err(" Error: Failed to delete events. (%d)\n", ret); pr_err(" Error: Failed to delete events. (%d)\n", ret);
return ret; return ret;
...@@ -483,3 +510,14 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -483,3 +510,14 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
} }
return 0; return 0;
} }
int cmd_probe(int argc, const char **argv, const char *prefix)
{
int ret;
init_params();
ret = __cmd_probe(argc, argv, prefix);
cleanup_params();
return ret;
}
...@@ -15,6 +15,8 @@ ...@@ -15,6 +15,8 @@
#include <errno.h> #include <errno.h>
#include <math.h> #include <math.h>
#include "asm/bug.h"
#include "hist.h" #include "hist.h"
#include "util.h" #include "util.h"
#include "sort.h" #include "sort.h"
...@@ -358,19 +360,14 @@ append_chain_children(struct callchain_node *root, ...@@ -358,19 +360,14 @@ append_chain_children(struct callchain_node *root,
/* lookup in childrens */ /* lookup in childrens */
while (*p) { while (*p) {
s64 ret; s64 ret;
struct callchain_list *cnode;
parent = *p; parent = *p;
rnode = rb_entry(parent, struct callchain_node, rb_node_in); rnode = rb_entry(parent, struct callchain_node, rb_node_in);
cnode = list_first_entry(&rnode->val, struct callchain_list,
list);
/* just check first entry */ /* If at least first entry matches, rely to children */
ret = match_chain(node, cnode); ret = append_chain(rnode, cursor, period);
if (ret == 0) { if (ret == 0)
append_chain(rnode, cursor, period);
goto inc_children_hit; goto inc_children_hit;
}
if (ret < 0) if (ret < 0)
p = &parent->rb_left; p = &parent->rb_left;
...@@ -391,11 +388,11 @@ append_chain(struct callchain_node *root, ...@@ -391,11 +388,11 @@ append_chain(struct callchain_node *root,
struct callchain_cursor *cursor, struct callchain_cursor *cursor,
u64 period) u64 period)
{ {
struct callchain_cursor_node *curr_snap = cursor->curr;
struct callchain_list *cnode; struct callchain_list *cnode;
u64 start = cursor->pos; u64 start = cursor->pos;
bool found = false; bool found = false;
u64 matches; u64 matches;
int cmp = 0;
/* /*
* Lookup in the current node * Lookup in the current node
...@@ -410,7 +407,8 @@ append_chain(struct callchain_node *root, ...@@ -410,7 +407,8 @@ append_chain(struct callchain_node *root,
if (!node) if (!node)
break; break;
if (match_chain(node, cnode) != 0) cmp = match_chain(node, cnode);
if (cmp)
break; break;
found = true; found = true;
...@@ -420,9 +418,8 @@ append_chain(struct callchain_node *root, ...@@ -420,9 +418,8 @@ append_chain(struct callchain_node *root,
/* matches not, relay no the parent */ /* matches not, relay no the parent */
if (!found) { if (!found) {
cursor->curr = curr_snap; WARN_ONCE(!cmp, "Chain comparison error\n");
cursor->pos = start; return cmp;
return -1;
} }
matches = cursor->pos - start; matches = cursor->pos - start;
......
...@@ -94,19 +94,20 @@ struct comm *comm__new(const char *str, u64 timestamp) ...@@ -94,19 +94,20 @@ struct comm *comm__new(const char *str, u64 timestamp)
return comm; return comm;
} }
void comm__override(struct comm *comm, const char *str, u64 timestamp) int comm__override(struct comm *comm, const char *str, u64 timestamp)
{ {
struct comm_str *old = comm->comm_str; struct comm_str *new, *old = comm->comm_str;
comm->comm_str = comm_str__findnew(str, &comm_str_root); new = comm_str__findnew(str, &comm_str_root);
if (!comm->comm_str) { if (!new)
comm->comm_str = old; return -ENOMEM;
return;
}
comm->start = timestamp; comm_str__get(new);
comm_str__get(comm->comm_str);
comm_str__put(old); comm_str__put(old);
comm->comm_str = new;
comm->start = timestamp;
return 0;
} }
void comm__free(struct comm *comm) void comm__free(struct comm *comm)
......
...@@ -16,6 +16,6 @@ struct comm { ...@@ -16,6 +16,6 @@ struct comm {
void comm__free(struct comm *comm); void comm__free(struct comm *comm);
struct comm *comm__new(const char *str, u64 timestamp); struct comm *comm__new(const char *str, u64 timestamp);
const char *comm__str(const struct comm *comm); const char *comm__str(const struct comm *comm);
void comm__override(struct comm *comm, const char *str, u64 timestamp); int comm__override(struct comm *comm, const char *str, u64 timestamp);
#endif /* __PERF_COMM_H */ #endif /* __PERF_COMM_H */
...@@ -72,6 +72,7 @@ static int e_snprintf(char *str, size_t size, const char *format, ...) ...@@ -72,6 +72,7 @@ static int e_snprintf(char *str, size_t size, const char *format, ...)
static char *synthesize_perf_probe_point(struct perf_probe_point *pp); static char *synthesize_perf_probe_point(struct perf_probe_point *pp);
static int convert_name_to_addr(struct perf_probe_event *pev, static int convert_name_to_addr(struct perf_probe_event *pev,
const char *exec); const char *exec);
static void clear_probe_trace_event(struct probe_trace_event *tev);
static struct machine machine; static struct machine machine;
/* Initialize symbol maps and path of vmlinux/modules */ /* Initialize symbol maps and path of vmlinux/modules */
...@@ -172,54 +173,6 @@ const char *kernel_get_module_path(const char *module) ...@@ -172,54 +173,6 @@ const char *kernel_get_module_path(const char *module)
return (dso) ? dso->long_name : NULL; return (dso) ? dso->long_name : NULL;
} }
#ifdef HAVE_DWARF_SUPPORT
/* Copied from unwind.c */
static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
GElf_Shdr *shp, const char *name)
{
Elf_Scn *sec = NULL;
while ((sec = elf_nextscn(elf, sec)) != NULL) {
char *str;
gelf_getshdr(sec, shp);
str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
if (!strcmp(name, str))
break;
}
return sec;
}
static int get_text_start_address(const char *exec, unsigned long *address)
{
Elf *elf;
GElf_Ehdr ehdr;
GElf_Shdr shdr;
int fd, ret = -ENOENT;
fd = open(exec, O_RDONLY);
if (fd < 0)
return -errno;
elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
if (elf == NULL)
return -EINVAL;
if (gelf_getehdr(elf, &ehdr) == NULL)
goto out;
if (!elf_section_by_name(elf, &ehdr, &shdr, ".text"))
goto out;
*address = shdr.sh_addr - shdr.sh_offset;
ret = 0;
out:
elf_end(elf);
return ret;
}
#endif
static int init_user_exec(void) static int init_user_exec(void)
{ {
int ret = 0; int ret = 0;
...@@ -340,6 +293,34 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp, ...@@ -340,6 +293,34 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
return 0; return 0;
} }
static int get_text_start_address(const char *exec, unsigned long *address)
{
Elf *elf;
GElf_Ehdr ehdr;
GElf_Shdr shdr;
int fd, ret = -ENOENT;
fd = open(exec, O_RDONLY);
if (fd < 0)
return -errno;
elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
if (elf == NULL)
return -EINVAL;
if (gelf_getehdr(elf, &ehdr) == NULL)
goto out;
if (!elf_section_by_name(elf, &ehdr, &shdr, ".text", NULL))
goto out;
*address = shdr.sh_addr - shdr.sh_offset;
ret = 0;
out:
elf_end(elf);
return ret;
}
static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs, static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs,
int ntevs, const char *exec) int ntevs, const char *exec)
{ {
...@@ -407,6 +388,14 @@ static int add_module_to_probe_trace_events(struct probe_trace_event *tevs, ...@@ -407,6 +388,14 @@ static int add_module_to_probe_trace_events(struct probe_trace_event *tevs,
return ret; return ret;
} }
static void clear_probe_trace_events(struct probe_trace_event *tevs, int ntevs)
{
int i;
for (i = 0; i < ntevs; i++)
clear_probe_trace_event(tevs + i);
}
/* Try to find perf_probe_event with debuginfo */ /* Try to find perf_probe_event with debuginfo */
static int try_to_find_probe_trace_events(struct perf_probe_event *pev, static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
struct probe_trace_event **tevs, struct probe_trace_event **tevs,
...@@ -442,6 +431,10 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev, ...@@ -442,6 +431,10 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
ret = add_module_to_probe_trace_events(*tevs, ret = add_module_to_probe_trace_events(*tevs,
ntevs, target); ntevs, target);
} }
if (ret < 0) {
clear_probe_trace_events(*tevs, ntevs);
zfree(tevs);
}
return ret < 0 ? ret : ntevs; return ret < 0 ? ret : ntevs;
} }
...@@ -781,6 +774,28 @@ int show_available_vars(struct perf_probe_event *pevs __maybe_unused, ...@@ -781,6 +774,28 @@ int show_available_vars(struct perf_probe_event *pevs __maybe_unused,
} }
#endif #endif
void line_range__clear(struct line_range *lr)
{
struct line_node *ln;
free(lr->function);
free(lr->file);
free(lr->path);
free(lr->comp_dir);
while (!list_empty(&lr->line_list)) {
ln = list_first_entry(&lr->line_list, struct line_node, list);
list_del(&ln->list);
free(ln);
}
memset(lr, 0, sizeof(*lr));
}
void line_range__init(struct line_range *lr)
{
memset(lr, 0, sizeof(*lr));
INIT_LIST_HEAD(&lr->line_list);
}
static int parse_line_num(char **ptr, int *val, const char *what) static int parse_line_num(char **ptr, int *val, const char *what)
{ {
const char *start = *ptr; const char *start = *ptr;
......
...@@ -120,6 +120,12 @@ extern void clear_perf_probe_event(struct perf_probe_event *pev); ...@@ -120,6 +120,12 @@ extern void clear_perf_probe_event(struct perf_probe_event *pev);
/* Command string to line-range */ /* Command string to line-range */
extern int parse_line_range_desc(const char *cmd, struct line_range *lr); extern int parse_line_range_desc(const char *cmd, struct line_range *lr);
/* Release line range members */
extern void line_range__clear(struct line_range *lr);
/* Initialize line range */
extern void line_range__init(struct line_range *lr);
/* Internal use: Return kernel/module path */ /* Internal use: Return kernel/module path */
extern const char *kernel_get_module_path(const char *module); extern const char *kernel_get_module_path(const char *module);
......
...@@ -136,9 +136,8 @@ static size_t elf_addr_to_index(Elf *elf, GElf_Addr addr) ...@@ -136,9 +136,8 @@ static size_t elf_addr_to_index(Elf *elf, GElf_Addr addr)
return -1; return -1;
} }
static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
GElf_Shdr *shp, const char *name, GElf_Shdr *shp, const char *name, size_t *idx)
size_t *idx)
{ {
Elf_Scn *sec = NULL; Elf_Scn *sec = NULL;
size_t cnt = 1; size_t cnt = 1;
......
...@@ -52,6 +52,11 @@ static inline char *bfd_demangle(void __maybe_unused *v, ...@@ -52,6 +52,11 @@ static inline char *bfd_demangle(void __maybe_unused *v,
# define PERF_ELF_C_READ_MMAP ELF_C_READ # define PERF_ELF_C_READ_MMAP ELF_C_READ
#endif #endif
#ifdef HAVE_LIBELF_SUPPORT
extern Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
GElf_Shdr *shp, const char *name, size_t *idx);
#endif
#ifndef DMGL_PARAMS #ifndef DMGL_PARAMS
#define DMGL_PARAMS (1 << 0) /* Include function args */ #define DMGL_PARAMS (1 << 0) /* Include function args */
#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */ #define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */
......
...@@ -66,10 +66,13 @@ struct comm *thread__comm(const struct thread *thread) ...@@ -66,10 +66,13 @@ struct comm *thread__comm(const struct thread *thread)
int thread__set_comm(struct thread *thread, const char *str, u64 timestamp) int thread__set_comm(struct thread *thread, const char *str, u64 timestamp)
{ {
struct comm *new, *curr = thread__comm(thread); struct comm *new, *curr = thread__comm(thread);
int err;
/* Override latest entry if it had no specific time coverage */ /* Override latest entry if it had no specific time coverage */
if (!curr->start) { if (!curr->start) {
comm__override(curr, str, timestamp); err = comm__override(curr, str, timestamp);
if (err)
return err;
} else { } else {
new = comm__new(str, timestamp); new = comm__new(str, timestamp);
if (!new) if (!new)
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include "session.h" #include "session.h"
#include "perf_regs.h" #include "perf_regs.h"
#include "unwind.h" #include "unwind.h"
#include "symbol.h"
#include "util.h" #include "util.h"
extern int extern int
...@@ -158,23 +159,6 @@ static int __dw_read_encoded_value(u8 **p, u8 *end, u64 *val, ...@@ -158,23 +159,6 @@ static int __dw_read_encoded_value(u8 **p, u8 *end, u64 *val,
__v; \ __v; \
}) })
static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
GElf_Shdr *shp, const char *name)
{
Elf_Scn *sec = NULL;
while ((sec = elf_nextscn(elf, sec)) != NULL) {
char *str;
gelf_getshdr(sec, shp);
str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
if (!strcmp(name, str))
break;
}
return sec;
}
static u64 elf_section_offset(int fd, const char *name) static u64 elf_section_offset(int fd, const char *name)
{ {
Elf *elf; Elf *elf;
...@@ -190,7 +174,7 @@ static u64 elf_section_offset(int fd, const char *name) ...@@ -190,7 +174,7 @@ static u64 elf_section_offset(int fd, const char *name)
if (gelf_getehdr(elf, &ehdr) == NULL) if (gelf_getehdr(elf, &ehdr) == NULL)
break; break;
if (!elf_section_by_name(elf, &ehdr, &shdr, name)) if (!elf_section_by_name(elf, &ehdr, &shdr, name, NULL))
break; break;
offset = shdr.sh_offset; offset = shdr.sh_offset;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment