Commit 47c1ded7 authored by Ingo Molnar's avatar Ingo Molnar

Merge tag 'perf-urgent-for-mingo-4.12-20170608' of...

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

Pull perf/urgent fixes from Arnaldo Carvalho de Melo:

 - Fixes for handling compressed kernel modules (Namhyung Kim)

 - Fix handling old style build-id cache ($HOME/.debug/) (Namhyung Kim)

 - 'perf script' python/perl documentation fixes: outdated comments,
   invalid code snippets, etc (SeongJae Park)
Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parents cc1582c2 b89fe63f
......@@ -240,9 +240,13 @@ Add a probe on schedule() function 12th line with recording cpu local variable:
or
./perf probe --add='schedule:12 cpu'
this will add one or more probes which has the name start with "schedule".
Add one or more probes which has the name start with "schedule".
Add probes on lines in schedule() function which calls update_rq_clock().
./perf probe schedule*
or
./perf probe --add='schedule*'
Add probes on lines in schedule() function which calls update_rq_clock().
./perf probe 'schedule;update_rq_clock*'
or
......
......@@ -39,7 +39,7 @@ EVENT HANDLERS
When perf script is invoked using a trace script, a user-defined
'handler function' is called for each event in the trace. If there's
no handler function defined for a given event type, the event is
ignored (or passed to a 'trace_handled' function, see below) and the
ignored (or passed to a 'trace_unhandled' function, see below) and the
next event is processed.
Most of the event's field values are passed as arguments to the
......
......@@ -149,10 +149,8 @@ def raw_syscalls__sys_enter(event_name, context, common_cpu,
print "id=%d, args=%s\n" % \
(id, args),
def trace_unhandled(event_name, context, common_cpu, common_secs, common_nsecs,
common_pid, common_comm):
print_header(event_name, common_cpu, common_secs, common_nsecs,
common_pid, common_comm)
def trace_unhandled(event_name, context, event_fields_dict):
print ' '.join(['%s=%s'%(k,str(v))for k,v in sorted(event_fields_dict.items())])
def print_header(event_name, cpu, secs, nsecs, pid, comm):
print "%-20s %5u %05u.%09u %8u %-20s " % \
......@@ -321,7 +319,7 @@ So those are the essential steps in writing and running a script. The
process can be generalized to any tracepoint or set of tracepoints
you're interested in - basically find the tracepoint(s) you're
interested in by looking at the list of available events shown by
'perf list' and/or look in /sys/kernel/debug/tracing events for
'perf list' and/or look in /sys/kernel/debug/tracing/events/ for
detailed event and field info, record the corresponding trace data
using 'perf record', passing it the list of interesting events,
generate a skeleton script using 'perf script -g python' and modify the
......@@ -334,7 +332,7 @@ right place, you can have your script listed alongside the other
scripts listed by the 'perf script -l' command e.g.:
----
root@tropicana:~# perf script -l
# perf script -l
List of available trace scripts:
wakeup-latency system-wide min/max/avg wakeup latency
rw-by-file <comm> r/w activity for a program, by file
......@@ -383,8 +381,6 @@ source tree:
----
# ls -al kernel-source/tools/perf/scripts/python
root@tropicana:/home/trz/src/tip# ls -al tools/perf/scripts/python
total 32
drwxr-xr-x 4 trz trz 4096 2010-01-26 22:30 .
drwxr-xr-x 4 trz trz 4096 2010-01-26 22:29 ..
......@@ -399,7 +395,7 @@ otherwise your script won't show up at run-time), 'perf script -l'
should show a new entry for your script:
----
root@tropicana:~# perf script -l
# perf script -l
List of available trace scripts:
wakeup-latency system-wide min/max/avg wakeup latency
rw-by-file <comm> r/w activity for a program, by file
......@@ -437,7 +433,7 @@ EVENT HANDLERS
When perf script is invoked using a trace script, a user-defined
'handler function' is called for each event in the trace. If there's
no handler function defined for a given event type, the event is
ignored (or passed to a 'trace_handled' function, see below) and the
ignored (or passed to a 'trace_unhandled' function, see below) and the
next event is processed.
Most of the event's field values are passed as arguments to the
......@@ -532,7 +528,7 @@ can implement a set of optional functions:
gives scripts a chance to do setup tasks:
----
def trace_begin:
def trace_begin():
pass
----
......@@ -541,7 +537,7 @@ def trace_begin:
as display results:
----
def trace_end:
def trace_end():
pass
----
......@@ -550,8 +546,7 @@ def trace_end:
of common arguments are passed into it:
----
def trace_unhandled(event_name, context, common_cpu, common_secs,
common_nsecs, common_pid, common_comm):
def trace_unhandled(event_name, context, event_fields_dict):
pass
----
......
......@@ -229,6 +229,8 @@ static int read_object_code(u64 addr, size_t len, u8 cpumode,
unsigned char buf2[BUFSZ];
size_t ret_len;
u64 objdump_addr;
const char *objdump_name;
char decomp_name[KMOD_DECOMP_LEN];
int ret;
pr_debug("Reading object code for memory address: %#"PRIx64"\n", addr);
......@@ -289,9 +291,25 @@ static int read_object_code(u64 addr, size_t len, u8 cpumode,
state->done[state->done_cnt++] = al.map->start;
}
objdump_name = al.map->dso->long_name;
if (dso__needs_decompress(al.map->dso)) {
if (dso__decompress_kmodule_path(al.map->dso, objdump_name,
decomp_name,
sizeof(decomp_name)) < 0) {
pr_debug("decompression failed\n");
return -1;
}
objdump_name = decomp_name;
}
/* Read the object code using objdump */
objdump_addr = map__rip_2objdump(al.map, al.addr);
ret = read_via_objdump(al.map->dso->long_name, objdump_addr, buf2, len);
ret = read_via_objdump(objdump_name, objdump_addr, buf2, len);
if (dso__needs_decompress(al.map->dso))
unlink(objdump_name);
if (ret > 0) {
/*
* The kernel maps are inaccurate - assume objdump is right in
......
......@@ -1321,6 +1321,7 @@ static int dso__disassemble_filename(struct dso *dso, char *filename, size_t fil
char linkname[PATH_MAX];
char *build_id_filename;
char *build_id_path = NULL;
char *pos;
if (dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS &&
!dso__is_kcore(dso))
......@@ -1340,6 +1341,13 @@ static int dso__disassemble_filename(struct dso *dso, char *filename, size_t fil
if (!build_id_path)
return -1;
/*
* old style build-id cache has name of XX/XXXXXXX.. while
* new style has XX/XXXXXXX../{elf,kallsyms,vdso}.
* extract the build-id part of dirname in the new style only.
*/
pos = strrchr(build_id_path, '/');
if (pos && strlen(pos) < SBUILD_ID_SIZE - 2)
dirname(build_id_path);
if (dso__is_kcore(dso) ||
......@@ -1423,31 +1431,10 @@ int symbol__disassemble(struct symbol *sym, struct map *map, const char *arch_na
sizeof(symfs_filename));
}
} else if (dso__needs_decompress(dso)) {
char tmp[PATH_MAX];
struct kmod_path m;
int fd;
bool ret;
if (kmod_path__parse_ext(&m, symfs_filename))
goto out;
snprintf(tmp, PATH_MAX, "/tmp/perf-kmod-XXXXXX");
fd = mkstemp(tmp);
if (fd < 0) {
free(m.ext);
goto out;
}
ret = decompress_to_file(m.ext, symfs_filename, fd);
if (ret)
pr_err("Cannot decompress %s %s\n", m.ext, symfs_filename);
free(m.ext);
close(fd);
char tmp[KMOD_DECOMP_LEN];
if (!ret)
if (dso__decompress_kmodule_path(dso, symfs_filename,
tmp, sizeof(tmp)) < 0)
goto out;
strcpy(symfs_filename, tmp);
......
......@@ -278,51 +278,6 @@ char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size)
return bf;
}
bool dso__build_id_is_kmod(const struct dso *dso, char *bf, size_t size)
{
char *id_name = NULL, *ch;
struct stat sb;
char sbuild_id[SBUILD_ID_SIZE];
if (!dso->has_build_id)
goto err;
build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id);
id_name = build_id_cache__linkname(sbuild_id, NULL, 0);
if (!id_name)
goto err;
if (access(id_name, F_OK))
goto err;
if (lstat(id_name, &sb) == -1)
goto err;
if ((size_t)sb.st_size > size - 1)
goto err;
if (readlink(id_name, bf, size - 1) < 0)
goto err;
bf[sb.st_size] = '\0';
/*
* link should be:
* ../../lib/modules/4.4.0-rc4/kernel/net/ipv4/netfilter/nf_nat_ipv4.ko/a09fe3eb3147dafa4e3b31dbd6257e4d696bdc92
*/
ch = strrchr(bf, '/');
if (!ch)
goto err;
if (ch - 3 < bf)
goto err;
free(id_name);
return strncmp(".ko", ch - 3, 3) == 0;
err:
pr_err("Invalid build id: %s\n", id_name ? :
dso->long_name ? :
dso->short_name ? :
"[unknown]");
free(id_name);
return false;
}
#define dsos__for_each_with_build_id(pos, head) \
list_for_each_entry(pos, head, node) \
if (!pos->has_build_id) \
......
......@@ -17,7 +17,6 @@ char *build_id_cache__kallsyms_path(const char *sbuild_id, char *bf,
size_t size);
char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size);
bool dso__build_id_is_kmod(const struct dso *dso, char *bf, size_t size);
int build_id__mark_dso_hit(struct perf_tool *tool, union perf_event *event,
struct perf_sample *sample, struct perf_evsel *evsel,
......
......@@ -248,6 +248,64 @@ bool dso__needs_decompress(struct dso *dso)
dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE_COMP;
}
static int decompress_kmodule(struct dso *dso, const char *name, char *tmpbuf)
{
int fd = -1;
struct kmod_path m;
if (!dso__needs_decompress(dso))
return -1;
if (kmod_path__parse_ext(&m, dso->long_name))
return -1;
if (!m.comp)
goto out;
fd = mkstemp(tmpbuf);
if (fd < 0) {
dso->load_errno = errno;
goto out;
}
if (!decompress_to_file(m.ext, name, fd)) {
dso->load_errno = DSO_LOAD_ERRNO__DECOMPRESSION_FAILURE;
close(fd);
fd = -1;
}
out:
free(m.ext);
return fd;
}
int dso__decompress_kmodule_fd(struct dso *dso, const char *name)
{
char tmpbuf[] = KMOD_DECOMP_NAME;
int fd;
fd = decompress_kmodule(dso, name, tmpbuf);
unlink(tmpbuf);
return fd;
}
int dso__decompress_kmodule_path(struct dso *dso, const char *name,
char *pathname, size_t len)
{
char tmpbuf[] = KMOD_DECOMP_NAME;
int fd;
fd = decompress_kmodule(dso, name, tmpbuf);
if (fd < 0) {
unlink(tmpbuf);
return -1;
}
strncpy(pathname, tmpbuf, len);
close(fd);
return 0;
}
/*
* Parses kernel module specified in @path and updates
* @m argument like:
......@@ -396,7 +454,7 @@ static int do_open(char *name)
static int __open_dso(struct dso *dso, struct machine *machine)
{
int fd;
int fd = -EINVAL;
char *root_dir = (char *)"";
char *name = malloc(PATH_MAX);
......@@ -407,15 +465,30 @@ static int __open_dso(struct dso *dso, struct machine *machine)
root_dir = machine->root_dir;
if (dso__read_binary_type_filename(dso, dso->binary_type,
root_dir, name, PATH_MAX)) {
free(name);
return -EINVAL;
}
root_dir, name, PATH_MAX))
goto out;
if (!is_regular_file(name))
return -EINVAL;
goto out;
if (dso__needs_decompress(dso)) {
char newpath[KMOD_DECOMP_LEN];
size_t len = sizeof(newpath);
if (dso__decompress_kmodule_path(dso, name, newpath, len) < 0) {
fd = -dso->load_errno;
goto out;
}
strcpy(name, newpath);
}
fd = do_open(name);
if (dso__needs_decompress(dso))
unlink(name);
out:
free(name);
return fd;
}
......
......@@ -244,6 +244,12 @@ bool is_supported_compression(const char *ext);
bool is_kernel_module(const char *pathname, int cpumode);
bool decompress_to_file(const char *ext, const char *filename, int output_fd);
bool dso__needs_decompress(struct dso *dso);
int dso__decompress_kmodule_fd(struct dso *dso, const char *name);
int dso__decompress_kmodule_path(struct dso *dso, const char *name,
char *pathname, size_t len);
#define KMOD_DECOMP_NAME "/tmp/perf-kmod-XXXXXX"
#define KMOD_DECOMP_LEN sizeof(KMOD_DECOMP_NAME)
struct kmod_path {
char *name;
......
......@@ -1219,7 +1219,7 @@ static int python_generate_script(struct pevent *pevent, const char *outfile)
fprintf(ofp, "# be retrieved using Python functions of the form "
"common_*(context).\n");
fprintf(ofp, "# See the perf-trace-python Documentation for the list "
fprintf(ofp, "# See the perf-script-python Documentation for the list "
"of available functions.\n\n");
fprintf(ofp, "import os\n");
......
......@@ -637,40 +637,6 @@ static int dso__swap_init(struct dso *dso, unsigned char eidata)
return 0;
}
static int decompress_kmodule(struct dso *dso, const char *name,
enum dso_binary_type type)
{
int fd = -1;
char tmpbuf[] = "/tmp/perf-kmod-XXXXXX";
struct kmod_path m;
if (type != DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP &&
type != DSO_BINARY_TYPE__GUEST_KMODULE_COMP &&
type != DSO_BINARY_TYPE__BUILD_ID_CACHE)
return -1;
if (kmod_path__parse_ext(&m, dso->long_name) || !m.comp)
return -1;
fd = mkstemp(tmpbuf);
if (fd < 0) {
dso->load_errno = errno;
goto out;
}
if (!decompress_to_file(m.ext, name, fd)) {
dso->load_errno = DSO_LOAD_ERRNO__DECOMPRESSION_FAILURE;
close(fd);
fd = -1;
}
unlink(tmpbuf);
out:
free(m.ext);
return fd;
}
bool symsrc__possibly_runtime(struct symsrc *ss)
{
return ss->dynsym || ss->opdsec;
......@@ -702,9 +668,11 @@ int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name,
int fd;
if (dso__needs_decompress(dso)) {
fd = decompress_kmodule(dso, name, type);
fd = dso__decompress_kmodule_fd(dso, name);
if (fd < 0)
return -1;
type = dso->symtab_type;
} else {
fd = open(name, O_RDONLY);
if (fd < 0) {
......
......@@ -1562,10 +1562,6 @@ int dso__load(struct dso *dso, struct map *map)
if (!runtime_ss && syms_ss)
runtime_ss = syms_ss;
if (syms_ss && syms_ss->type == DSO_BINARY_TYPE__BUILD_ID_CACHE)
if (dso__build_id_is_kmod(dso, name, PATH_MAX))
kmod = true;
if (syms_ss)
ret = dso__load_sym(dso, map, syms_ss, runtime_ss, kmod);
else
......
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