提交 45e6af06 编写于 作者: I 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: NArnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: NIngo Molnar <mingo@kernel.org>
......@@ -5560,6 +5560,52 @@ int pevent_register_print_function(struct pevent *pevent,
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: the handle to the pevent
......@@ -5584,20 +5630,9 @@ int pevent_register_event_handler(struct pevent *pevent, int id,
struct event_format *event;
struct event_handler *handle;
if (id >= 0) {
/* search by id */
event = pevent_find_event(pevent, id);
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;
}
event = pevent_search_event(pevent, id, sys_name, event_name);
if (event == NULL)
goto not_found;
pr_stat("overriding event (%d) %s:%s with new print handler",
event->id, event->system, event->name);
......@@ -5637,6 +5672,79 @@ int pevent_register_event_handler(struct pevent *pevent, int id,
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
*/
......
......@@ -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,
const char *sys_name, const char *event_name,
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,
pevent_func_handler func,
enum pevent_func_arg_type ret_type,
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_field(struct event_format *event, const char *name);
......
......@@ -22,3 +22,9 @@ int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
PEVENT_FUNC_ARG_VOID);
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)
{
int i, x;
pevent_unregister_event_handler(pevent, -1, "ftrace", "function",
function_handler, NULL);
for (i = 0; i <= cpus; i++) {
for (x = 0; x < fstack[i].size && fstack[i].stack[x]; x++)
free(fstack[i].stack[x]);
......
......@@ -76,3 +76,13 @@ int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
timer_start_handler, NULL);
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)
PEVENT_FUNC_ARG_VOID);
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)
call_site_handler, NULL);
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)
PEVENT_FUNC_ARG_VOID);
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)
drv_bss_info_changed, NULL);
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)
sched_wakeup_handler, NULL);
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)
PEVENT_FUNC_ARG_VOID);
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)
PEVENT_FUNC_ARG_VOID);
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:
clean:
$(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:
#
......
......@@ -59,7 +59,7 @@ static struct {
struct perf_probe_event events[MAX_PROBES];
struct strlist *dellist;
struct line_range line_range;
const char *target;
char *target;
int max_probe_points;
struct strfilter *filter;
} params;
......@@ -98,7 +98,10 @@ static int set_target(const char *ptr)
* short module name.
*/
if (!params.target && ptr && *ptr == '/') {
params.target = ptr;
params.target = strdup(ptr);
if (!params.target)
return -ENOMEM;
found = 1;
buf = ptr + (strlen(ptr) - 3);
......@@ -116,6 +119,9 @@ static int parse_probe_event_argv(int argc, const char **argv)
char *buf;
found_target = set_target(argv[0]);
if (found_target < 0)
return found_target;
if (found_target && argc == 1)
return 0;
......@@ -217,7 +223,6 @@ static int opt_show_lines(const struct option *opt __maybe_unused,
params.show_lines = true;
ret = parse_line_range_desc(str, &params.line_range);
INIT_LIST_HEAD(&params.line_range.line_list);
return ret;
}
......@@ -263,7 +268,28 @@ static int opt_set_filter(const struct option *opt __maybe_unused,
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[] = {
"perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]",
......@@ -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,
params.uprobes);
strfilter__delete(params.filter);
params.filter = NULL;
if (ret < 0)
pr_err(" Error: Failed to show functions."
" (%d)\n", ret);
......@@ -456,6 +483,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
params.filter,
params.show_ext_vars);
strfilter__delete(params.filter);
params.filter = NULL;
if (ret < 0)
pr_err(" Error: Failed to show vars. (%d)\n", ret);
return ret;
......@@ -464,7 +492,6 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
if (params.dellist) {
ret = del_perf_probe_events(params.dellist);
strlist__delete(params.dellist);
if (ret < 0) {
pr_err(" Error: Failed to delete events. (%d)\n", ret);
return ret;
......@@ -483,3 +510,14 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
}
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 @@
#include <errno.h>
#include <math.h>
#include "asm/bug.h"
#include "hist.h"
#include "util.h"
#include "sort.h"
......@@ -358,19 +360,14 @@ append_chain_children(struct callchain_node *root,
/* lookup in childrens */
while (*p) {
s64 ret;
struct callchain_list *cnode;
parent = *p;
rnode = rb_entry(parent, struct callchain_node, rb_node_in);
cnode = list_first_entry(&rnode->val, struct callchain_list,
list);
/* just check first entry */
ret = match_chain(node, cnode);
if (ret == 0) {
append_chain(rnode, cursor, period);
/* If at least first entry matches, rely to children */
ret = append_chain(rnode, cursor, period);
if (ret == 0)
goto inc_children_hit;
}
if (ret < 0)
p = &parent->rb_left;
......@@ -391,11 +388,11 @@ append_chain(struct callchain_node *root,
struct callchain_cursor *cursor,
u64 period)
{
struct callchain_cursor_node *curr_snap = cursor->curr;
struct callchain_list *cnode;
u64 start = cursor->pos;
bool found = false;
u64 matches;
int cmp = 0;
/*
* Lookup in the current node
......@@ -410,7 +407,8 @@ append_chain(struct callchain_node *root,
if (!node)
break;
if (match_chain(node, cnode) != 0)
cmp = match_chain(node, cnode);
if (cmp)
break;
found = true;
......@@ -420,9 +418,8 @@ append_chain(struct callchain_node *root,
/* matches not, relay no the parent */
if (!found) {
cursor->curr = curr_snap;
cursor->pos = start;
return -1;
WARN_ONCE(!cmp, "Chain comparison error\n");
return cmp;
}
matches = cursor->pos - start;
......
......@@ -94,19 +94,20 @@ struct comm *comm__new(const char *str, u64 timestamp)
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);
if (!comm->comm_str) {
comm->comm_str = old;
return;
}
new = comm_str__findnew(str, &comm_str_root);
if (!new)
return -ENOMEM;
comm->start = timestamp;
comm_str__get(comm->comm_str);
comm_str__get(new);
comm_str__put(old);
comm->comm_str = new;
comm->start = timestamp;
return 0;
}
void comm__free(struct comm *comm)
......
......@@ -16,6 +16,6 @@ struct comm {
void comm__free(struct comm *comm);
struct comm *comm__new(const char *str, u64 timestamp);
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 */
......@@ -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 int convert_name_to_addr(struct perf_probe_event *pev,
const char *exec);
static void clear_probe_trace_event(struct probe_trace_event *tev);
static struct machine machine;
/* Initialize symbol maps and path of vmlinux/modules */
......@@ -172,54 +173,6 @@ const char *kernel_get_module_path(const char *module)
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)
{
int ret = 0;
......@@ -340,6 +293,34 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
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,
int ntevs, const char *exec)
{
......@@ -407,6 +388,14 @@ static int add_module_to_probe_trace_events(struct probe_trace_event *tevs,
return ret;
}
static void clear_probe_trace_events(struct probe_trace_event *tevs, int ntevs)
{
int i;
for (i = 0; i < ntevs; i++)
clear_probe_trace_event(tevs + i);
}
/* Try to find perf_probe_event with debuginfo */
static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
struct probe_trace_event **tevs,
......@@ -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,
ntevs, target);
}
if (ret < 0) {
clear_probe_trace_events(*tevs, ntevs);
zfree(tevs);
}
return ret < 0 ? ret : ntevs;
}
......@@ -781,6 +774,28 @@ int show_available_vars(struct perf_probe_event *pevs __maybe_unused,
}
#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)
{
const char *start = *ptr;
......
......@@ -120,6 +120,12 @@ extern void clear_perf_probe_event(struct perf_probe_event *pev);
/* Command string to line-range */
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 */
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)
return -1;
}
static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
GElf_Shdr *shp, const char *name,
size_t *idx)
Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
GElf_Shdr *shp, const char *name, size_t *idx)
{
Elf_Scn *sec = NULL;
size_t cnt = 1;
......
......@@ -52,6 +52,11 @@ static inline char *bfd_demangle(void __maybe_unused *v,
# define PERF_ELF_C_READ_MMAP ELF_C_READ
#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
#define DMGL_PARAMS (1 << 0) /* Include function args */
#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */
......
......@@ -66,10 +66,13 @@ struct comm *thread__comm(const struct thread *thread)
int thread__set_comm(struct thread *thread, const char *str, u64 timestamp)
{
struct comm *new, *curr = thread__comm(thread);
int err;
/* Override latest entry if it had no specific time coverage */
if (!curr->start) {
comm__override(curr, str, timestamp);
err = comm__override(curr, str, timestamp);
if (err)
return err;
} else {
new = comm__new(str, timestamp);
if (!new)
......
......@@ -28,6 +28,7 @@
#include "session.h"
#include "perf_regs.h"
#include "unwind.h"
#include "symbol.h"
#include "util.h"
extern int
......@@ -158,23 +159,6 @@ static int __dw_read_encoded_value(u8 **p, u8 *end, u64 *val,
__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)
{
Elf *elf;
......@@ -190,7 +174,7 @@ static u64 elf_section_offset(int fd, const char *name)
if (gelf_getehdr(elf, &ehdr) == NULL)
break;
if (!elf_section_by_name(elf, &ehdr, &shdr, name))
if (!elf_section_by_name(elf, &ehdr, &shdr, name, NULL))
break;
offset = shdr.sh_offset;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册