Merge branch 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull perf fixes from Ingo Molnar: "This is mostly tooling fixes, plus an instruction pointer filtering fix. It's more fixes than usual - Arnaldo got back from a longer vacation and there was a backlog" * 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (27 commits) perf symbols: Kill dso__build_id_is_kmod() perf symbols: Keep DSO->symtab_type after decompress perf tests: Decompress kernel module before objdump perf tools: Consolidate error path in __open_dso() perf tools: Decompress kernel module when reading DSO data perf annotate: Use dso__decompress_kmodule_path() perf tools: Introduce dso__decompress_kmodule_{fd,path} perf tools: Fix a memory leak in __open_dso() perf annotate: Fix symbolic link of build-id cache perf/core: Drop kernel samples even though :u is specified perf script python: Remove dups in documentation examples perf script python: Updated trace_unhandled() signature perf script python: Fix wrong code snippets in documentation perf script: Fix documentation errors perf script: Fix outdated comment for perf-trace-python perf probe: Fix examples section of documentation perf report: Ensure the perf DSO mapping matches what libdw sees perf report: Include partial stacks unwound with libdw perf annotate: Add missing powerpc triplet perf test: Disable breakpoint signal tests for powerpc ...
This commit is contained in:
commit
f701d860af
@ -7316,6 +7316,21 @@ int perf_event_account_interrupt(struct perf_event *event)
|
||||
return __perf_event_account_interrupt(event, 1);
|
||||
}
|
||||
|
||||
static bool sample_is_allowed(struct perf_event *event, struct pt_regs *regs)
|
||||
{
|
||||
/*
|
||||
* Due to interrupt latency (AKA "skid"), we may enter the
|
||||
* kernel before taking an overflow, even if the PMU is only
|
||||
* counting user events.
|
||||
* To avoid leaking information to userspace, we must always
|
||||
* reject kernel samples when exclude_kernel is set.
|
||||
*/
|
||||
if (event->attr.exclude_kernel && !user_mode(regs))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Generic event overflow handling, sampling.
|
||||
*/
|
||||
@ -7336,6 +7351,12 @@ static int __perf_event_overflow(struct perf_event *event,
|
||||
|
||||
ret = __perf_event_account_interrupt(event, throttle);
|
||||
|
||||
/*
|
||||
* For security, drop the skid kernel samples if necessary.
|
||||
*/
|
||||
if (!sample_is_allowed(event, regs))
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* XXX event_limit might not quite work as expected on inherited
|
||||
* events
|
||||
|
@ -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
|
||||
----
|
||||
|
||||
|
@ -26,6 +26,7 @@ const char *const arm64_triplets[] = {
|
||||
|
||||
const char *const powerpc_triplets[] = {
|
||||
"powerpc-unknown-linux-gnu-",
|
||||
"powerpc-linux-gnu-",
|
||||
"powerpc64-unknown-linux-gnu-",
|
||||
"powerpc64-linux-gnu-",
|
||||
"powerpc64le-linux-gnu-",
|
||||
|
@ -1578,6 +1578,7 @@ static void print_header(int argc, const char **argv)
|
||||
static void print_footer(void)
|
||||
{
|
||||
FILE *output = stat_config.output;
|
||||
int n;
|
||||
|
||||
if (!null_run)
|
||||
fprintf(output, "\n");
|
||||
@ -1590,7 +1591,9 @@ static void print_footer(void)
|
||||
}
|
||||
fprintf(output, "\n\n");
|
||||
|
||||
if (print_free_counters_hint)
|
||||
if (print_free_counters_hint &&
|
||||
sysctl__read_int("kernel/nmi_watchdog", &n) >= 0 &&
|
||||
n > 0)
|
||||
fprintf(output,
|
||||
"Some events weren't counted. Try disabling the NMI watchdog:\n"
|
||||
" echo 0 > /proc/sys/kernel/nmi_watchdog\n"
|
||||
|
@ -681,6 +681,10 @@ static struct syscall_fmt {
|
||||
{ .name = "mlockall", .errmsg = true,
|
||||
.arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
|
||||
{ .name = "mmap", .hexret = true,
|
||||
/* The standard mmap maps to old_mmap on s390x */
|
||||
#if defined(__s390x__)
|
||||
.alias = "old_mmap",
|
||||
#endif
|
||||
.arg_scnprintf = { [0] = SCA_HEX, /* addr */
|
||||
[2] = SCA_MMAP_PROT, /* prot */
|
||||
[3] = SCA_MMAP_FLAGS, /* flags */ }, },
|
||||
|
@ -288,3 +288,17 @@ int test__bp_signal(int subtest __maybe_unused)
|
||||
return count1 == 1 && overflows == 3 && count2 == 3 && overflows_2 == 3 && count3 == 2 ?
|
||||
TEST_OK : TEST_FAIL;
|
||||
}
|
||||
|
||||
bool test__bp_signal_is_supported(void)
|
||||
{
|
||||
/*
|
||||
* The powerpc so far does not have support to even create
|
||||
* instruction breakpoint using the perf event interface.
|
||||
* Once it's there we can release this.
|
||||
*/
|
||||
#ifdef __powerpc__
|
||||
return false;
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
@ -97,10 +97,12 @@ static struct test generic_tests[] = {
|
||||
{
|
||||
.desc = "Breakpoint overflow signal handler",
|
||||
.func = test__bp_signal,
|
||||
.is_supported = test__bp_signal_is_supported,
|
||||
},
|
||||
{
|
||||
.desc = "Breakpoint overflow sampling",
|
||||
.func = test__bp_signal_overflow,
|
||||
.is_supported = test__bp_signal_is_supported,
|
||||
},
|
||||
{
|
||||
.desc = "Number of exit events of a simple workload",
|
||||
@ -401,6 +403,11 @@ static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist)
|
||||
if (!perf_test__matches(t, curr, argc, argv))
|
||||
continue;
|
||||
|
||||
if (t->is_supported && !t->is_supported()) {
|
||||
pr_debug("%2d: %-*s: Disabled\n", i, width, t->desc);
|
||||
continue;
|
||||
}
|
||||
|
||||
pr_info("%2d: %-*s:", i, width, t->desc);
|
||||
|
||||
if (intlist__find(skiplist, i)) {
|
||||
|
@ -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
|
||||
|
@ -34,6 +34,7 @@ struct test {
|
||||
int (*get_nr)(void);
|
||||
const char *(*get_desc)(int subtest);
|
||||
} subtest;
|
||||
bool (*is_supported)(void);
|
||||
};
|
||||
|
||||
/* Tests */
|
||||
@ -99,6 +100,8 @@ const char *test__clang_subtest_get_desc(int subtest);
|
||||
int test__clang_subtest_get_nr(void);
|
||||
int test__unit_number__scnprint(int subtest);
|
||||
|
||||
bool test__bp_signal_is_supported(void);
|
||||
|
||||
#if defined(__arm__) || defined(__aarch64__)
|
||||
#ifdef HAVE_DWARF_UNWIND_SUPPORT
|
||||
struct thread;
|
||||
|
@ -239,10 +239,20 @@ static int jump__parse(struct arch *arch __maybe_unused, struct ins_operands *op
|
||||
const char *s = strchr(ops->raw, '+');
|
||||
const char *c = strchr(ops->raw, ',');
|
||||
|
||||
if (c++ != NULL)
|
||||
/*
|
||||
* skip over possible up to 2 operands to get to address, e.g.:
|
||||
* tbnz w0, #26, ffff0000083cd190 <security_file_permission+0xd0>
|
||||
*/
|
||||
if (c++ != NULL) {
|
||||
ops->target.addr = strtoull(c, NULL, 16);
|
||||
else
|
||||
if (!ops->target.addr) {
|
||||
c = strchr(c, ',');
|
||||
if (c++ != NULL)
|
||||
ops->target.addr = strtoull(c, NULL, 16);
|
||||
}
|
||||
} else {
|
||||
ops->target.addr = strtoull(ops->raw, NULL, 16);
|
||||
}
|
||||
|
||||
if (s++ != NULL) {
|
||||
ops->target.offset = strtoull(s, NULL, 16);
|
||||
@ -257,10 +267,27 @@ static int jump__parse(struct arch *arch __maybe_unused, struct ins_operands *op
|
||||
static int jump__scnprintf(struct ins *ins, char *bf, size_t size,
|
||||
struct ins_operands *ops)
|
||||
{
|
||||
const char *c = strchr(ops->raw, ',');
|
||||
|
||||
if (!ops->target.addr || ops->target.offset < 0)
|
||||
return ins__raw_scnprintf(ins, bf, size, ops);
|
||||
|
||||
return scnprintf(bf, size, "%-6.6s %" PRIx64, ins->name, ops->target.offset);
|
||||
if (c != NULL) {
|
||||
const char *c2 = strchr(c + 1, ',');
|
||||
|
||||
/* check for 3-op insn */
|
||||
if (c2 != NULL)
|
||||
c = c2;
|
||||
c++;
|
||||
|
||||
/* mirror arch objdump's space-after-comma style */
|
||||
if (*c == ' ')
|
||||
c++;
|
||||
}
|
||||
|
||||
return scnprintf(bf, size, "%-6.6s %.*s%" PRIx64,
|
||||
ins->name, c ? c - ops->raw : 0, ops->raw,
|
||||
ops->target.offset);
|
||||
}
|
||||
|
||||
static struct ins_ops jump_ops = {
|
||||
@ -1294,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))
|
||||
@ -1313,7 +1341,14 @@ static int dso__disassemble_filename(struct dso *dso, char *filename, size_t fil
|
||||
if (!build_id_path)
|
||||
return -1;
|
||||
|
||||
dirname(build_id_path);
|
||||
/*
|
||||
* 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) ||
|
||||
readlink(build_id_path, linkname, sizeof(linkname)) < 0 ||
|
||||
@ -1396,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;
|
||||
char tmp[KMOD_DECOMP_LEN];
|
||||
|
||||
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);
|
||||
|
||||
if (!ret)
|
||||
if (dso__decompress_kmodule_path(dso, symfs_filename,
|
||||
tmp, sizeof(tmp)) < 0)
|
||||
goto out;
|
||||
|
||||
strcpy(symfs_filename, tmp);
|
||||
@ -1429,7 +1443,7 @@ int symbol__disassemble(struct symbol *sym, struct map *map, const char *arch_na
|
||||
snprintf(command, sizeof(command),
|
||||
"%s %s%s --start-address=0x%016" PRIx64
|
||||
" --stop-address=0x%016" PRIx64
|
||||
" -l -d %s %s -C %s 2>/dev/null|grep -v %s:|expand",
|
||||
" -l -d %s %s -C \"%s\" 2>/dev/null|grep -v \"%s:\"|expand",
|
||||
objdump_path ? objdump_path : "objdump",
|
||||
disassembler_style ? "-M " : "",
|
||||
disassembler_style ? disassembler_style : "",
|
||||
|
@ -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:
|
||||
@ -335,6 +393,21 @@ int __kmod_path__parse(struct kmod_path *m, const char *path,
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dso__set_module_info(struct dso *dso, struct kmod_path *m,
|
||||
struct machine *machine)
|
||||
{
|
||||
if (machine__is_host(machine))
|
||||
dso->symtab_type = DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE;
|
||||
else
|
||||
dso->symtab_type = DSO_BINARY_TYPE__GUEST_KMODULE;
|
||||
|
||||
/* _KMODULE_COMP should be next to _KMODULE */
|
||||
if (m->kmod && m->comp)
|
||||
dso->symtab_type++;
|
||||
|
||||
dso__set_short_name(dso, strdup(m->name), true);
|
||||
}
|
||||
|
||||
/*
|
||||
* Global list of open DSOs and the counter.
|
||||
*/
|
||||
@ -381,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);
|
||||
|
||||
@ -392,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;
|
||||
@ -259,6 +265,9 @@ int __kmod_path__parse(struct kmod_path *m, const char *path,
|
||||
#define kmod_path__parse_name(__m, __p) __kmod_path__parse(__m, __p, true , false)
|
||||
#define kmod_path__parse_ext(__m, __p) __kmod_path__parse(__m, __p, false, true)
|
||||
|
||||
void dso__set_module_info(struct dso *dso, struct kmod_path *m,
|
||||
struct machine *machine);
|
||||
|
||||
/*
|
||||
* The dso__data_* external interface provides following functions:
|
||||
* dso__data_get_fd
|
||||
|
@ -1469,8 +1469,16 @@ static int __event_process_build_id(struct build_id_event *bev,
|
||||
|
||||
dso__set_build_id(dso, &bev->build_id);
|
||||
|
||||
if (!is_kernel_module(filename, cpumode))
|
||||
dso->kernel = dso_type;
|
||||
if (dso_type != DSO_TYPE_USER) {
|
||||
struct kmod_path m = { .name = NULL, };
|
||||
|
||||
if (!kmod_path__parse_name(&m, filename) && m.kmod)
|
||||
dso__set_module_info(dso, &m, machine);
|
||||
else
|
||||
dso->kernel = dso_type;
|
||||
|
||||
free(m.name);
|
||||
}
|
||||
|
||||
build_id__sprintf(dso->build_id, sizeof(dso->build_id),
|
||||
sbuild_id);
|
||||
|
@ -572,16 +572,7 @@ static struct dso *machine__findnew_module_dso(struct machine *machine,
|
||||
if (dso == NULL)
|
||||
goto out_unlock;
|
||||
|
||||
if (machine__is_host(machine))
|
||||
dso->symtab_type = DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE;
|
||||
else
|
||||
dso->symtab_type = DSO_BINARY_TYPE__GUEST_KMODULE;
|
||||
|
||||
/* _KMODULE_COMP should be next to _KMODULE */
|
||||
if (m->kmod && m->comp)
|
||||
dso->symtab_type++;
|
||||
|
||||
dso__set_short_name(dso, strdup(m->name), true);
|
||||
dso__set_module_info(dso, m, machine);
|
||||
dso__set_long_name(dso, strdup(filename), true);
|
||||
}
|
||||
|
||||
|
@ -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,43 +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 (type == DSO_BINARY_TYPE__BUILD_ID_CACHE)
|
||||
name = dso->long_name;
|
||||
|
||||
if (kmod_path__parse_ext(&m, 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;
|
||||
@ -705,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
|
||||
|
@ -39,6 +39,14 @@ static int __report_module(struct addr_location *al, u64 ip,
|
||||
return 0;
|
||||
|
||||
mod = dwfl_addrmodule(ui->dwfl, ip);
|
||||
if (mod) {
|
||||
Dwarf_Addr s;
|
||||
|
||||
dwfl_module_info(mod, NULL, &s, NULL, NULL, NULL, NULL, NULL);
|
||||
if (s != al->map->start)
|
||||
mod = 0;
|
||||
}
|
||||
|
||||
if (!mod)
|
||||
mod = dwfl_report_elf(ui->dwfl, dso->short_name,
|
||||
dso->long_name, -1, al->map->start,
|
||||
@ -224,7 +232,7 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
|
||||
|
||||
err = dwfl_getthread_frames(ui->dwfl, thread->tid, frame_callback, ui);
|
||||
|
||||
if (err && !ui->max_stack)
|
||||
if (err && ui->max_stack != max_stack)
|
||||
err = 0;
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user