forked from Minki/linux
perf/core improvements and fixes:
Developer stuff: o More prep work to support Intel PT: (Adrian Hunter) - Polishing 'script' BTS output - 'inject' can specify --kallsym - VDSO is per machine, not a global var - Expose data addr lookup functions previously private to 'script' - Large mmap fixes in events processing o Fix build on gcc 4.4.7 (Arnaldo Carvalho de Melo) o Event ordering fixes (Jiri Olsa) o Include standard stringify macros in power pc code (Sukadev Bhattiprolu) Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJT0nkWAAoJENZQFvNTUqpAEJcP/0yIjEORa1J2pKFueyLSaY3K JBeol2NJLfj5fxxNjmHdTl8uV/UGorOobxkQ+s3Liujg8hGQL97KonHrMXSw4/Oo Lj14qOlC3YiFzvbpU3U5NaK4t3OPCLB8paQWBw8/Wx0nDtqz70538hTq55mNd9JZ RfSBfcJ7gedvZNfZoU0+GjukT6c+waOj9ADKUeIoefXyrvspggkFyh4UeeP2Y4ri FlkzDPsKndD+eZhG4ZrN7VPuEUyn4OymYPcJ7eie7kAXlEydNQECoXsLEWo8gygR emC4Dk4qfDhmPESJm5EDeeB3OYca810rSmtMcmiBG2bfqrIQhDlo+DrKYddIUYQl HJp2NlK1gMd2I0cwW/80G4Fkz4y2mxsdbps9/76qFMnLSGLrNTbmh95Fgyw5kaP9 UIU0hXALdNUlKTBpNHFuhjSufVbFE3qRSsH2wXWM3FOkJFMksw0hSqa8NgQ1Y2IZ Iy6EfOhkqr5PkrgokHgEuhqB7akaD/I5NW089gr5vmbORkxnamaNuSXHuV1RqftM uupYvFUN/WGDhFyUtDJ2sFOpRC8P6XHFVFDCT7wJ2JsdQP7KGbhgi5emSnTld8so 4N5gJSYg7FGK16I0eF+Ro5t2TxdOk3LaXES98h8RFNvAqYZMT8iDirAz9ACAUnJ3 wES53HBJn/O7eKD4LqGO =W4Hp -----END PGP SIGNATURE----- Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo: Infrastructure changes: o More prep work to support Intel PT: (Adrian Hunter) - Polishing 'script' BTS output - 'inject' can specify --kallsym - VDSO is per machine, not a global var - Expose data addr lookup functions previously private to 'script' - Large mmap fixes in events processing o Fix build on gcc 4.4.7 (Arnaldo Carvalho de Melo) o Event ordering fixes (Jiri Olsa) o Include standard stringify macros in power pc code (Sukadev Bhattiprolu) Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
commit
068f1d3f45
@ -41,6 +41,9 @@ OPTIONS
|
||||
tasks slept. sched_switch contains a callchain where a task slept and
|
||||
sched_stat contains a timeslice how long a task slept.
|
||||
|
||||
--kallsyms=<file>::
|
||||
kallsyms pathname
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
linkperf:perf-record[1], linkperf:perf-report[1], linkperf:perf-archive[1]
|
||||
|
@ -5,9 +5,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "../../util/header.h"
|
||||
|
||||
#define __stringify_1(x) #x
|
||||
#define __stringify(x) __stringify_1(x)
|
||||
#include "../../util/util.h"
|
||||
|
||||
#define mfspr(rn) ({unsigned long rval; \
|
||||
asm volatile("mfspr %0," __stringify(rn) \
|
||||
|
@ -37,3 +37,12 @@ int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc,
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u64 rdtsc(void)
|
||||
{
|
||||
unsigned int low, high;
|
||||
|
||||
asm volatile("rdtsc" : "=a" (low), "=d" (high));
|
||||
|
||||
return low | ((u64)high) << 32;
|
||||
}
|
||||
|
@ -439,6 +439,8 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
"where and how long tasks slept"),
|
||||
OPT_INCR('v', "verbose", &verbose,
|
||||
"be more verbose (show build ids, etc)"),
|
||||
OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name, "file",
|
||||
"kallsyms pathname"),
|
||||
OPT_END()
|
||||
};
|
||||
const char * const inject_usage[] = {
|
||||
|
@ -238,6 +238,7 @@ static struct perf_event_header finished_round_event = {
|
||||
|
||||
static int record__mmap_read_all(struct record *rec)
|
||||
{
|
||||
u64 bytes_written = rec->bytes_written;
|
||||
int i;
|
||||
int rc = 0;
|
||||
|
||||
@ -250,7 +251,11 @@ static int record__mmap_read_all(struct record *rec)
|
||||
}
|
||||
}
|
||||
|
||||
if (perf_header__has_feat(&rec->session->header, HEADER_TRACING_DATA))
|
||||
/*
|
||||
* Mark the round finished in case we wrote
|
||||
* at least one event.
|
||||
*/
|
||||
if (bytes_written != rec->bytes_written)
|
||||
rc = record__write(rec, &finished_round_event, sizeof(finished_round_event));
|
||||
|
||||
out:
|
||||
|
@ -358,27 +358,6 @@ static void print_sample_start(struct perf_sample *sample,
|
||||
}
|
||||
}
|
||||
|
||||
static bool is_bts_event(struct perf_event_attr *attr)
|
||||
{
|
||||
return ((attr->type == PERF_TYPE_HARDWARE) &&
|
||||
(attr->config & PERF_COUNT_HW_BRANCH_INSTRUCTIONS) &&
|
||||
(attr->sample_period == 1));
|
||||
}
|
||||
|
||||
static bool sample_addr_correlates_sym(struct perf_event_attr *attr)
|
||||
{
|
||||
if ((attr->type == PERF_TYPE_SOFTWARE) &&
|
||||
((attr->config == PERF_COUNT_SW_PAGE_FAULTS) ||
|
||||
(attr->config == PERF_COUNT_SW_PAGE_FAULTS_MIN) ||
|
||||
(attr->config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)))
|
||||
return true;
|
||||
|
||||
if (is_bts_event(attr))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void print_sample_addr(union perf_event *event,
|
||||
struct perf_sample *sample,
|
||||
struct machine *machine,
|
||||
@ -386,24 +365,13 @@ static void print_sample_addr(union perf_event *event,
|
||||
struct perf_event_attr *attr)
|
||||
{
|
||||
struct addr_location al;
|
||||
u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
|
||||
|
||||
printf("%16" PRIx64, sample->addr);
|
||||
|
||||
if (!sample_addr_correlates_sym(attr))
|
||||
return;
|
||||
|
||||
thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION,
|
||||
sample->addr, &al);
|
||||
if (!al.map)
|
||||
thread__find_addr_map(thread, machine, cpumode, MAP__VARIABLE,
|
||||
sample->addr, &al);
|
||||
|
||||
al.cpu = sample->cpu;
|
||||
al.sym = NULL;
|
||||
|
||||
if (al.map)
|
||||
al.sym = map__find_symbol(al.map, al.addr, NULL);
|
||||
perf_event__preprocess_sample_addr(event, sample, machine, thread, &al);
|
||||
|
||||
if (PRINT_FIELD(SYM)) {
|
||||
printf(" ");
|
||||
@ -427,25 +395,35 @@ static void print_sample_bts(union perf_event *event,
|
||||
struct addr_location *al)
|
||||
{
|
||||
struct perf_event_attr *attr = &evsel->attr;
|
||||
bool print_srcline_last = false;
|
||||
|
||||
/* print branch_from information */
|
||||
if (PRINT_FIELD(IP)) {
|
||||
if (!symbol_conf.use_callchain)
|
||||
printf(" ");
|
||||
else
|
||||
unsigned int print_opts = output[attr->type].print_ip_opts;
|
||||
|
||||
if (symbol_conf.use_callchain && sample->callchain) {
|
||||
printf("\n");
|
||||
perf_evsel__print_ip(evsel, sample, al,
|
||||
output[attr->type].print_ip_opts,
|
||||
} else {
|
||||
printf(" ");
|
||||
if (print_opts & PRINT_IP_OPT_SRCLINE) {
|
||||
print_srcline_last = true;
|
||||
print_opts &= ~PRINT_IP_OPT_SRCLINE;
|
||||
}
|
||||
}
|
||||
perf_evsel__print_ip(evsel, sample, al, print_opts,
|
||||
PERF_MAX_STACK_DEPTH);
|
||||
}
|
||||
|
||||
printf(" => ");
|
||||
|
||||
/* print branch_to information */
|
||||
if (PRINT_FIELD(ADDR) ||
|
||||
((evsel->attr.sample_type & PERF_SAMPLE_ADDR) &&
|
||||
!output[attr->type].user_set))
|
||||
!output[attr->type].user_set)) {
|
||||
printf(" => ");
|
||||
print_sample_addr(event, sample, al->machine, thread, attr);
|
||||
}
|
||||
|
||||
if (print_srcline_last)
|
||||
map__fprintf_srcline(al->map, al->addr, "\n ", stdout);
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
@ -1994,10 +1994,10 @@ static int perf_evlist__add_pgfault(struct perf_evlist *evlist,
|
||||
struct perf_event_attr attr = {
|
||||
.type = PERF_TYPE_SOFTWARE,
|
||||
.mmap_data = 1,
|
||||
.sample_period = 1,
|
||||
};
|
||||
|
||||
attr.config = config;
|
||||
attr.sample_period = 1;
|
||||
|
||||
event_attr_init(&attr);
|
||||
|
||||
|
@ -25,15 +25,6 @@
|
||||
} \
|
||||
}
|
||||
|
||||
static u64 rdtsc(void)
|
||||
{
|
||||
unsigned int low, high;
|
||||
|
||||
asm volatile("rdtsc" : "=a" (low), "=d" (high));
|
||||
|
||||
return low | ((u64)high) << 32;
|
||||
}
|
||||
|
||||
/**
|
||||
* test__perf_time_to_tsc - test converting perf time to TSC.
|
||||
*
|
||||
|
@ -1,3 +1,4 @@
|
||||
#include <sched.h>
|
||||
#include "util.h"
|
||||
#include "../perf.h"
|
||||
#include "cloexec.h"
|
||||
@ -14,9 +15,13 @@ static int perf_flag_probe(void)
|
||||
};
|
||||
int fd;
|
||||
int err;
|
||||
int cpu = sched_getcpu();
|
||||
|
||||
if (cpu < 0)
|
||||
cpu = 0;
|
||||
|
||||
/* check cloexec flag */
|
||||
fd = sys_perf_event_open(&attr, 0, -1, -1,
|
||||
fd = sys_perf_event_open(&attr, -1, cpu, -1,
|
||||
PERF_FLAG_FD_CLOEXEC);
|
||||
err = errno;
|
||||
|
||||
@ -30,7 +35,7 @@ static int perf_flag_probe(void)
|
||||
err, strerror(err));
|
||||
|
||||
/* not supported, confirm error related to PERF_FLAG_FD_CLOEXEC */
|
||||
fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
|
||||
fd = sys_perf_event_open(&attr, -1, cpu, -1, 0);
|
||||
err = errno;
|
||||
|
||||
if (WARN_ONCE(fd < 0,
|
||||
|
@ -216,7 +216,7 @@ static int open_dso(struct dso *dso, struct machine *machine)
|
||||
{
|
||||
int fd = __open_dso(dso, machine);
|
||||
|
||||
if (fd > 0) {
|
||||
if (fd >= 0) {
|
||||
dso__list_add(dso);
|
||||
/*
|
||||
* Check if we crossed the allowed number
|
||||
@ -331,26 +331,44 @@ int dso__data_fd(struct dso *dso, struct machine *machine)
|
||||
};
|
||||
int i = 0;
|
||||
|
||||
if (dso->data.status == DSO_DATA_STATUS_ERROR)
|
||||
return -1;
|
||||
|
||||
if (dso->data.fd >= 0)
|
||||
return dso->data.fd;
|
||||
goto out;
|
||||
|
||||
if (dso->binary_type != DSO_BINARY_TYPE__NOT_FOUND) {
|
||||
dso->data.fd = open_dso(dso, machine);
|
||||
return dso->data.fd;
|
||||
goto out;
|
||||
}
|
||||
|
||||
do {
|
||||
int fd;
|
||||
|
||||
dso->binary_type = binary_type_data[i++];
|
||||
|
||||
fd = open_dso(dso, machine);
|
||||
if (fd >= 0)
|
||||
return dso->data.fd = fd;
|
||||
dso->data.fd = open_dso(dso, machine);
|
||||
if (dso->data.fd >= 0)
|
||||
goto out;
|
||||
|
||||
} while (dso->binary_type != DSO_BINARY_TYPE__NOT_FOUND);
|
||||
out:
|
||||
if (dso->data.fd >= 0)
|
||||
dso->data.status = DSO_DATA_STATUS_OK;
|
||||
else
|
||||
dso->data.status = DSO_DATA_STATUS_ERROR;
|
||||
|
||||
return -EINVAL;
|
||||
return dso->data.fd;
|
||||
}
|
||||
|
||||
bool dso__data_status_seen(struct dso *dso, enum dso_data_status_seen by)
|
||||
{
|
||||
u32 flag = 1 << by;
|
||||
|
||||
if (dso->data.status_seen & flag)
|
||||
return true;
|
||||
|
||||
dso->data.status_seen |= flag;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -526,6 +544,28 @@ static int data_file_size(struct dso *dso)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* dso__data_size - Return dso data size
|
||||
* @dso: dso object
|
||||
* @machine: machine object
|
||||
*
|
||||
* Return: dso data size
|
||||
*/
|
||||
off_t dso__data_size(struct dso *dso, struct machine *machine)
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = dso__data_fd(dso, machine);
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
|
||||
if (data_file_size(dso))
|
||||
return -1;
|
||||
|
||||
/* For now just estimate dso data size is close to file size */
|
||||
return dso->data.file_size;
|
||||
}
|
||||
|
||||
static ssize_t data_read_offset(struct dso *dso, u64 offset,
|
||||
u8 *data, ssize_t size)
|
||||
{
|
||||
@ -701,6 +741,7 @@ struct dso *dso__new(const char *name)
|
||||
dso->symbols[i] = dso->symbol_names[i] = RB_ROOT;
|
||||
dso->data.cache = RB_ROOT;
|
||||
dso->data.fd = -1;
|
||||
dso->data.status = DSO_DATA_STATUS_UNKNOWN;
|
||||
dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND;
|
||||
dso->binary_type = DSO_BINARY_TYPE__NOT_FOUND;
|
||||
dso->is_64_bit = (sizeof(void *) == 8);
|
||||
@ -899,3 +940,14 @@ size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp)
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
enum dso_type dso__type(struct dso *dso, struct machine *machine)
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = dso__data_fd(dso, machine);
|
||||
if (fd < 0)
|
||||
return DSO__TYPE_UNKNOWN;
|
||||
|
||||
return dso__type_fd(fd);
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <linux/rbtree.h>
|
||||
#include <stdbool.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/bitops.h>
|
||||
#include "map.h"
|
||||
#include "build-id.h"
|
||||
|
||||
@ -40,6 +41,23 @@ enum dso_swap_type {
|
||||
DSO_SWAP__YES,
|
||||
};
|
||||
|
||||
enum dso_data_status {
|
||||
DSO_DATA_STATUS_ERROR = -1,
|
||||
DSO_DATA_STATUS_UNKNOWN = 0,
|
||||
DSO_DATA_STATUS_OK = 1,
|
||||
};
|
||||
|
||||
enum dso_data_status_seen {
|
||||
DSO_DATA_STATUS_SEEN_ITRACE,
|
||||
};
|
||||
|
||||
enum dso_type {
|
||||
DSO__TYPE_UNKNOWN,
|
||||
DSO__TYPE_64BIT,
|
||||
DSO__TYPE_32BIT,
|
||||
DSO__TYPE_X32BIT,
|
||||
};
|
||||
|
||||
#define DSO__SWAP(dso, type, val) \
|
||||
({ \
|
||||
type ____r = val; \
|
||||
@ -104,6 +122,8 @@ struct dso {
|
||||
struct {
|
||||
struct rb_root cache;
|
||||
int fd;
|
||||
int status;
|
||||
u32 status_seen;
|
||||
size_t file_size;
|
||||
struct list_head open_entry;
|
||||
} data;
|
||||
@ -154,6 +174,7 @@ int dso__read_binary_type_filename(const struct dso *dso, enum dso_binary_type t
|
||||
* The dso__data_* external interface provides following functions:
|
||||
* dso__data_fd
|
||||
* dso__data_close
|
||||
* dso__data_size
|
||||
* dso__data_read_offset
|
||||
* dso__data_read_addr
|
||||
*
|
||||
@ -191,11 +212,13 @@ int dso__read_binary_type_filename(const struct dso *dso, enum dso_binary_type t
|
||||
int dso__data_fd(struct dso *dso, struct machine *machine);
|
||||
void dso__data_close(struct dso *dso);
|
||||
|
||||
off_t dso__data_size(struct dso *dso, struct machine *machine);
|
||||
ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine,
|
||||
u64 offset, u8 *data, ssize_t size);
|
||||
ssize_t dso__data_read_addr(struct dso *dso, struct map *map,
|
||||
struct machine *machine, u64 addr,
|
||||
u8 *data, ssize_t size);
|
||||
bool dso__data_status_seen(struct dso *dso, enum dso_data_status_seen by);
|
||||
|
||||
struct map *dso__new_map(const char *name);
|
||||
struct dso *dso__kernel_findnew(struct machine *machine, const char *name,
|
||||
@ -230,4 +253,6 @@ static inline bool dso__is_kcore(struct dso *dso)
|
||||
|
||||
void dso__free_a2l(struct dso *dso);
|
||||
|
||||
enum dso_type dso__type(struct dso *dso, struct machine *machine);
|
||||
|
||||
#endif /* __PERF_DSO */
|
||||
|
@ -874,3 +874,45 @@ int perf_event__preprocess_sample(const union perf_event *event,
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool is_bts_event(struct perf_event_attr *attr)
|
||||
{
|
||||
return attr->type == PERF_TYPE_HARDWARE &&
|
||||
(attr->config & PERF_COUNT_HW_BRANCH_INSTRUCTIONS) &&
|
||||
attr->sample_period == 1;
|
||||
}
|
||||
|
||||
bool sample_addr_correlates_sym(struct perf_event_attr *attr)
|
||||
{
|
||||
if (attr->type == PERF_TYPE_SOFTWARE &&
|
||||
(attr->config == PERF_COUNT_SW_PAGE_FAULTS ||
|
||||
attr->config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
|
||||
attr->config == PERF_COUNT_SW_PAGE_FAULTS_MAJ))
|
||||
return true;
|
||||
|
||||
if (is_bts_event(attr))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void perf_event__preprocess_sample_addr(union perf_event *event,
|
||||
struct perf_sample *sample,
|
||||
struct machine *machine,
|
||||
struct thread *thread,
|
||||
struct addr_location *al)
|
||||
{
|
||||
u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
|
||||
|
||||
thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION,
|
||||
sample->addr, al);
|
||||
if (!al->map)
|
||||
thread__find_addr_map(thread, machine, cpumode, MAP__VARIABLE,
|
||||
sample->addr, al);
|
||||
|
||||
al->cpu = sample->cpu;
|
||||
al->sym = NULL;
|
||||
|
||||
if (al->map)
|
||||
al->sym = map__find_symbol(al->map, al->addr, NULL);
|
||||
}
|
||||
|
@ -288,6 +288,16 @@ int perf_event__preprocess_sample(const union perf_event *event,
|
||||
struct addr_location *al,
|
||||
struct perf_sample *sample);
|
||||
|
||||
struct thread;
|
||||
|
||||
bool is_bts_event(struct perf_event_attr *attr);
|
||||
bool sample_addr_correlates_sym(struct perf_event_attr *attr);
|
||||
void perf_event__preprocess_sample_addr(union perf_event *event,
|
||||
struct perf_sample *sample,
|
||||
struct machine *machine,
|
||||
struct thread *thread,
|
||||
struct addr_location *al);
|
||||
|
||||
const char *perf_event__name(unsigned int id);
|
||||
|
||||
size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type,
|
||||
|
@ -200,6 +200,47 @@ static int write_buildid(const char *name, size_t name_len, u8 *build_id,
|
||||
return write_padded(fd, name, name_len + 1, len);
|
||||
}
|
||||
|
||||
static int __dsos__hit_all(struct list_head *head)
|
||||
{
|
||||
struct dso *pos;
|
||||
|
||||
list_for_each_entry(pos, head, node)
|
||||
pos->hit = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int machine__hit_all_dsos(struct machine *machine)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = __dsos__hit_all(&machine->kernel_dsos);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return __dsos__hit_all(&machine->user_dsos);
|
||||
}
|
||||
|
||||
int dsos__hit_all(struct perf_session *session)
|
||||
{
|
||||
struct rb_node *nd;
|
||||
int err;
|
||||
|
||||
err = machine__hit_all_dsos(&session->machines.host);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
|
||||
struct machine *pos = rb_entry(nd, struct machine, rb_node);
|
||||
|
||||
err = machine__hit_all_dsos(pos);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __dsos__write_buildid_table(struct list_head *head,
|
||||
struct machine *machine,
|
||||
pid_t pid, u16 misc, int fd)
|
||||
@ -215,9 +256,9 @@ static int __dsos__write_buildid_table(struct list_head *head,
|
||||
if (!pos->hit)
|
||||
continue;
|
||||
|
||||
if (is_vdso_map(pos->short_name)) {
|
||||
name = (char *) VDSO__MAP_NAME;
|
||||
name_len = sizeof(VDSO__MAP_NAME) + 1;
|
||||
if (dso__is_vdso(pos)) {
|
||||
name = pos->short_name;
|
||||
name_len = pos->short_name_len + 1;
|
||||
} else if (dso__is_kcore(pos)) {
|
||||
machine__mmap_name(machine, nm, sizeof(nm));
|
||||
name = nm;
|
||||
@ -298,7 +339,7 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
|
||||
|
||||
len = scnprintf(filename, size, "%s%s%s",
|
||||
debugdir, slash ? "/" : "",
|
||||
is_vdso ? VDSO__MAP_NAME : realname);
|
||||
is_vdso ? DSO__NAME_VDSO : realname);
|
||||
if (mkdir_p(filename, 0755))
|
||||
goto out_free;
|
||||
|
||||
@ -386,7 +427,7 @@ static int dso__cache_build_id(struct dso *dso, struct machine *machine,
|
||||
const char *debugdir)
|
||||
{
|
||||
bool is_kallsyms = dso->kernel && dso->long_name[0] != '/';
|
||||
bool is_vdso = is_vdso_map(dso->short_name);
|
||||
bool is_vdso = dso__is_vdso(dso);
|
||||
const char *name = dso->long_name;
|
||||
char nm[PATH_MAX];
|
||||
|
||||
|
@ -151,6 +151,8 @@ int perf_event__process_build_id(struct perf_tool *tool,
|
||||
struct perf_session *session);
|
||||
bool is_perf_magic(u64 magic);
|
||||
|
||||
int dsos__hit_all(struct perf_session *session);
|
||||
|
||||
/*
|
||||
* arch specific callback
|
||||
*/
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "sort.h"
|
||||
#include "strlist.h"
|
||||
#include "thread.h"
|
||||
#include "vdso.h"
|
||||
#include <stdbool.h>
|
||||
#include <symbol/kallsyms.h>
|
||||
#include "unwind.h"
|
||||
@ -23,6 +24,8 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
|
||||
INIT_LIST_HEAD(&machine->dead_threads);
|
||||
machine->last_match = NULL;
|
||||
|
||||
machine->vdso_info = NULL;
|
||||
|
||||
machine->kmaps.machine = machine;
|
||||
machine->pid = pid;
|
||||
|
||||
@ -45,6 +48,8 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
|
||||
thread__set_comm(thread, comm, 0);
|
||||
}
|
||||
|
||||
machine->current_tid = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -103,7 +108,9 @@ void machine__exit(struct machine *machine)
|
||||
map_groups__exit(&machine->kmaps);
|
||||
dsos__delete(&machine->user_dsos);
|
||||
dsos__delete(&machine->kernel_dsos);
|
||||
vdso__exit(machine);
|
||||
zfree(&machine->root_dir);
|
||||
zfree(&machine->current_tid);
|
||||
}
|
||||
|
||||
void machine__delete(struct machine *machine)
|
||||
@ -1092,14 +1099,14 @@ int machine__process_mmap2_event(struct machine *machine,
|
||||
else
|
||||
type = MAP__FUNCTION;
|
||||
|
||||
map = map__new(&machine->user_dsos, event->mmap2.start,
|
||||
map = map__new(machine, event->mmap2.start,
|
||||
event->mmap2.len, event->mmap2.pgoff,
|
||||
event->mmap2.pid, event->mmap2.maj,
|
||||
event->mmap2.min, event->mmap2.ino,
|
||||
event->mmap2.ino_generation,
|
||||
event->mmap2.prot,
|
||||
event->mmap2.flags,
|
||||
event->mmap2.filename, type);
|
||||
event->mmap2.filename, type, thread);
|
||||
|
||||
if (map == NULL)
|
||||
goto out_problem;
|
||||
@ -1142,11 +1149,11 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *event
|
||||
else
|
||||
type = MAP__FUNCTION;
|
||||
|
||||
map = map__new(&machine->user_dsos, event->mmap.start,
|
||||
map = map__new(machine, event->mmap.start,
|
||||
event->mmap.len, event->mmap.pgoff,
|
||||
event->mmap.pid, 0, 0, 0, 0, 0, 0,
|
||||
event->mmap.filename,
|
||||
type);
|
||||
type, thread);
|
||||
|
||||
if (map == NULL)
|
||||
goto out_problem;
|
||||
@ -1481,3 +1488,46 @@ int __machine__synthesize_threads(struct machine *machine, struct perf_tool *too
|
||||
/* command specified */
|
||||
return 0;
|
||||
}
|
||||
|
||||
pid_t machine__get_current_tid(struct machine *machine, int cpu)
|
||||
{
|
||||
if (cpu < 0 || cpu >= MAX_NR_CPUS || !machine->current_tid)
|
||||
return -1;
|
||||
|
||||
return machine->current_tid[cpu];
|
||||
}
|
||||
|
||||
int machine__set_current_tid(struct machine *machine, int cpu, pid_t pid,
|
||||
pid_t tid)
|
||||
{
|
||||
struct thread *thread;
|
||||
|
||||
if (cpu < 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (!machine->current_tid) {
|
||||
int i;
|
||||
|
||||
machine->current_tid = calloc(MAX_NR_CPUS, sizeof(pid_t));
|
||||
if (!machine->current_tid)
|
||||
return -ENOMEM;
|
||||
for (i = 0; i < MAX_NR_CPUS; i++)
|
||||
machine->current_tid[i] = -1;
|
||||
}
|
||||
|
||||
if (cpu >= MAX_NR_CPUS) {
|
||||
pr_err("Requested CPU %d too large. ", cpu);
|
||||
pr_err("Consider raising MAX_NR_CPUS\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
machine->current_tid[cpu] = tid;
|
||||
|
||||
thread = machine__findnew_thread(machine, pid, tid);
|
||||
if (!thread)
|
||||
return -ENOMEM;
|
||||
|
||||
thread->cpu = cpu;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -20,6 +20,8 @@ union perf_event;
|
||||
|
||||
extern const char *ref_reloc_sym_names[];
|
||||
|
||||
struct vdso_info;
|
||||
|
||||
struct machine {
|
||||
struct rb_node rb_node;
|
||||
pid_t pid;
|
||||
@ -28,11 +30,13 @@ struct machine {
|
||||
struct rb_root threads;
|
||||
struct list_head dead_threads;
|
||||
struct thread *last_match;
|
||||
struct vdso_info *vdso_info;
|
||||
struct list_head user_dsos;
|
||||
struct list_head kernel_dsos;
|
||||
struct map_groups kmaps;
|
||||
struct map *vmlinux_maps[MAP__NR_TYPES];
|
||||
symbol_filter_t symbol_filter;
|
||||
pid_t *current_tid;
|
||||
};
|
||||
|
||||
static inline
|
||||
@ -191,4 +195,8 @@ int machine__synthesize_threads(struct machine *machine, struct target *target,
|
||||
perf_event__process, data_mmap);
|
||||
}
|
||||
|
||||
pid_t machine__get_current_tid(struct machine *machine, int cpu);
|
||||
int machine__set_current_tid(struct machine *machine, int cpu, pid_t pid,
|
||||
pid_t tid);
|
||||
|
||||
#endif /* __PERF_MACHINE_H */
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "build-id.h"
|
||||
#include "util.h"
|
||||
#include "debug.h"
|
||||
#include "machine.h"
|
||||
#include <linux/string.h>
|
||||
|
||||
const char *map_type__name[MAP__NR_TYPES] = {
|
||||
@ -137,10 +138,10 @@ void map__init(struct map *map, enum map_type type,
|
||||
map->erange_warned = false;
|
||||
}
|
||||
|
||||
struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
|
||||
struct map *map__new(struct machine *machine, u64 start, u64 len,
|
||||
u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino,
|
||||
u64 ino_gen, u32 prot, u32 flags, char *filename,
|
||||
enum map_type type)
|
||||
enum map_type type, struct thread *thread)
|
||||
{
|
||||
struct map *map = malloc(sizeof(*map));
|
||||
|
||||
@ -173,9 +174,9 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
|
||||
|
||||
if (vdso) {
|
||||
pgoff = 0;
|
||||
dso = vdso__dso_findnew(dsos__list);
|
||||
dso = vdso__dso_findnew(machine, thread);
|
||||
} else
|
||||
dso = __dsos__findnew(dsos__list, filename);
|
||||
dso = __dsos__findnew(&machine->user_dsos, filename);
|
||||
|
||||
if (dso == NULL)
|
||||
goto out_delete;
|
||||
|
@ -104,6 +104,7 @@ u64 map__rip_2objdump(struct map *map, u64 rip);
|
||||
u64 map__objdump_2mem(struct map *map, u64 ip);
|
||||
|
||||
struct symbol;
|
||||
struct thread;
|
||||
|
||||
/* map__for_each_symbol - iterate over the symbols in the given map
|
||||
*
|
||||
@ -119,10 +120,10 @@ typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym);
|
||||
|
||||
void map__init(struct map *map, enum map_type type,
|
||||
u64 start, u64 end, u64 pgoff, struct dso *dso);
|
||||
struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
|
||||
struct map *map__new(struct machine *machine, u64 start, u64 len,
|
||||
u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino,
|
||||
u64 ino_gen, u32 prot, u32 flags,
|
||||
char *filename, enum map_type type);
|
||||
char *filename, enum map_type type, struct thread *thread);
|
||||
struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
|
||||
void map__delete(struct map *map);
|
||||
struct map *map__clone(struct map *map);
|
||||
|
@ -14,7 +14,6 @@
|
||||
#include "util.h"
|
||||
#include "cpumap.h"
|
||||
#include "perf_regs.h"
|
||||
#include "vdso.h"
|
||||
|
||||
static int perf_session__open(struct perf_session *session)
|
||||
{
|
||||
@ -156,7 +155,6 @@ void perf_session__delete(struct perf_session *session)
|
||||
if (session->file)
|
||||
perf_data_file__close(session->file);
|
||||
free(session);
|
||||
vdso__exit();
|
||||
}
|
||||
|
||||
static int process_event_synth_tracing_data_stub(struct perf_tool *tool
|
||||
@ -511,6 +509,7 @@ static int flush_sample_queue(struct perf_session *s,
|
||||
os->last_flush = iter->timestamp;
|
||||
list_del(&iter->list);
|
||||
list_add(&iter->list, &os->sample_cache);
|
||||
os->nr_samples--;
|
||||
|
||||
if (show_progress)
|
||||
ui_progress__update(&prog, 1);
|
||||
@ -523,8 +522,6 @@ static int flush_sample_queue(struct perf_session *s,
|
||||
list_entry(head->prev, struct sample_queue, list);
|
||||
}
|
||||
|
||||
os->nr_samples = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -994,8 +991,10 @@ static int perf_session_deliver_event(struct perf_session *session,
|
||||
}
|
||||
}
|
||||
|
||||
static int perf_session__process_user_event(struct perf_session *session, union perf_event *event,
|
||||
struct perf_tool *tool, u64 file_offset)
|
||||
static s64 perf_session__process_user_event(struct perf_session *session,
|
||||
union perf_event *event,
|
||||
struct perf_tool *tool,
|
||||
u64 file_offset)
|
||||
{
|
||||
int fd = perf_data_file__fd(session->file);
|
||||
int err;
|
||||
@ -1037,7 +1036,7 @@ static void event_swap(union perf_event *event, bool sample_id_all)
|
||||
swap(event, sample_id_all);
|
||||
}
|
||||
|
||||
static int perf_session__process_event(struct perf_session *session,
|
||||
static s64 perf_session__process_event(struct perf_session *session,
|
||||
union perf_event *event,
|
||||
struct perf_tool *tool,
|
||||
u64 file_offset)
|
||||
@ -1148,7 +1147,7 @@ static int __perf_session__process_pipe_events(struct perf_session *session,
|
||||
union perf_event *event;
|
||||
uint32_t size, cur_size = 0;
|
||||
void *buf = NULL;
|
||||
int skip = 0;
|
||||
s64 skip = 0;
|
||||
u64 head;
|
||||
ssize_t err;
|
||||
void *p;
|
||||
@ -1277,13 +1276,13 @@ int __perf_session__process_events(struct perf_session *session,
|
||||
u64 file_size, struct perf_tool *tool)
|
||||
{
|
||||
int fd = perf_data_file__fd(session->file);
|
||||
u64 head, page_offset, file_offset, file_pos;
|
||||
u64 head, page_offset, file_offset, file_pos, size;
|
||||
int err, mmap_prot, mmap_flags, map_idx = 0;
|
||||
size_t mmap_size;
|
||||
char *buf, *mmaps[NUM_MMAPS];
|
||||
union perf_event *event;
|
||||
uint32_t size;
|
||||
struct ui_progress prog;
|
||||
s64 skip;
|
||||
|
||||
perf_tool__fill_defaults(tool);
|
||||
|
||||
@ -1344,7 +1343,8 @@ more:
|
||||
size = event->header.size;
|
||||
|
||||
if (size < sizeof(struct perf_event_header) ||
|
||||
perf_session__process_event(session, event, tool, file_pos) < 0) {
|
||||
(skip = perf_session__process_event(session, event, tool, file_pos))
|
||||
< 0) {
|
||||
pr_err("%#" PRIx64 " [%#x]: failed to process type: %d\n",
|
||||
file_offset + head, event->header.size,
|
||||
event->header.type);
|
||||
@ -1352,6 +1352,9 @@ more:
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
if (skip)
|
||||
size += skip;
|
||||
|
||||
head += size;
|
||||
file_pos += size;
|
||||
|
||||
|
@ -622,7 +622,7 @@ int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name,
|
||||
GElf_Shdr shdr;
|
||||
ss->adjust_symbols = (ehdr.e_type == ET_EXEC ||
|
||||
ehdr.e_type == ET_REL ||
|
||||
is_vdso_map(dso->short_name) ||
|
||||
dso__is_vdso(dso) ||
|
||||
elf_section_by_name(elf, &ehdr, &shdr,
|
||||
".gnu.prelink_undo",
|
||||
NULL) != NULL);
|
||||
@ -1028,6 +1028,39 @@ int file__read_maps(int fd, bool exe, mapfn_t mapfn, void *data,
|
||||
return err;
|
||||
}
|
||||
|
||||
enum dso_type dso__type_fd(int fd)
|
||||
{
|
||||
enum dso_type dso_type = DSO__TYPE_UNKNOWN;
|
||||
GElf_Ehdr ehdr;
|
||||
Elf_Kind ek;
|
||||
Elf *elf;
|
||||
|
||||
elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
|
||||
if (elf == NULL)
|
||||
goto out;
|
||||
|
||||
ek = elf_kind(elf);
|
||||
if (ek != ELF_K_ELF)
|
||||
goto out_end;
|
||||
|
||||
if (gelf_getclass(elf) == ELFCLASS64) {
|
||||
dso_type = DSO__TYPE_64BIT;
|
||||
goto out_end;
|
||||
}
|
||||
|
||||
if (gelf_getehdr(elf, &ehdr) == NULL)
|
||||
goto out_end;
|
||||
|
||||
if (ehdr.e_machine == EM_X86_64)
|
||||
dso_type = DSO__TYPE_X32BIT;
|
||||
else
|
||||
dso_type = DSO__TYPE_32BIT;
|
||||
out_end:
|
||||
elf_end(elf);
|
||||
out:
|
||||
return dso_type;
|
||||
}
|
||||
|
||||
static int copy_bytes(int from, off_t from_offs, int to, off_t to_offs, u64 len)
|
||||
{
|
||||
ssize_t r;
|
||||
|
@ -305,6 +305,27 @@ static int fd__is_64_bit(int fd)
|
||||
return e_ident[EI_CLASS] == ELFCLASS64;
|
||||
}
|
||||
|
||||
enum dso_type dso__type_fd(int fd)
|
||||
{
|
||||
Elf64_Ehdr ehdr;
|
||||
int ret;
|
||||
|
||||
ret = fd__is_64_bit(fd);
|
||||
if (ret < 0)
|
||||
return DSO__TYPE_UNKNOWN;
|
||||
|
||||
if (ret)
|
||||
return DSO__TYPE_64BIT;
|
||||
|
||||
if (readn(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr))
|
||||
return DSO__TYPE_UNKNOWN;
|
||||
|
||||
if (ehdr.e_machine == EM_X86_64)
|
||||
return DSO__TYPE_X32BIT;
|
||||
|
||||
return DSO__TYPE_32BIT;
|
||||
}
|
||||
|
||||
int dso__load_sym(struct dso *dso, struct map *map __maybe_unused,
|
||||
struct symsrc *ss,
|
||||
struct symsrc *runtime_ss __maybe_unused,
|
||||
|
@ -243,6 +243,8 @@ struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,
|
||||
struct symbol *dso__first_symbol(struct dso *dso, enum map_type type);
|
||||
struct symbol *dso__next_symbol(struct symbol *sym);
|
||||
|
||||
enum dso_type dso__type_fd(int fd);
|
||||
|
||||
int filename__read_build_id(const char *filename, void *bf, size_t size);
|
||||
int sysfs__read_build_id(const char *filename, void *bf, size_t size);
|
||||
int modules__parse(const char *filename, void *arg,
|
||||
|
@ -34,6 +34,7 @@ struct thread *thread__new(pid_t pid, pid_t tid)
|
||||
thread->pid_ = pid;
|
||||
thread->tid = tid;
|
||||
thread->ppid = -1;
|
||||
thread->cpu = -1;
|
||||
INIT_LIST_HEAD(&thread->comm_list);
|
||||
|
||||
comm_str = malloc(32);
|
||||
|
@ -17,6 +17,7 @@ struct thread {
|
||||
pid_t pid_; /* Not all tools update this */
|
||||
pid_t tid;
|
||||
pid_t ppid;
|
||||
int cpu;
|
||||
char shortname[3];
|
||||
bool comm_set;
|
||||
bool dead; /* if set thread has exited */
|
||||
|
@ -23,3 +23,8 @@ u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc)
|
||||
return tc->time_zero + quot * tc->time_mult +
|
||||
((rem * tc->time_mult) >> tc->time_shift);
|
||||
}
|
||||
|
||||
u64 __weak rdtsc(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -7,5 +7,6 @@
|
||||
|
||||
u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc);
|
||||
u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc);
|
||||
u64 rdtsc(void);
|
||||
|
||||
#endif
|
||||
|
@ -11,11 +11,34 @@
|
||||
#include "vdso.h"
|
||||
#include "util.h"
|
||||
#include "symbol.h"
|
||||
#include "machine.h"
|
||||
#include "linux/string.h"
|
||||
#include "debug.h"
|
||||
|
||||
static bool vdso_found;
|
||||
static char vdso_file[] = "/tmp/perf-vdso.so-XXXXXX";
|
||||
#define VDSO__TEMP_FILE_NAME "/tmp/perf-vdso.so-XXXXXX"
|
||||
|
||||
struct vdso_file {
|
||||
bool found;
|
||||
bool error;
|
||||
char temp_file_name[sizeof(VDSO__TEMP_FILE_NAME)];
|
||||
const char *dso_name;
|
||||
};
|
||||
|
||||
struct vdso_info {
|
||||
struct vdso_file vdso;
|
||||
};
|
||||
|
||||
static struct vdso_info *vdso_info__new(void)
|
||||
{
|
||||
static const struct vdso_info vdso_info_init = {
|
||||
.vdso = {
|
||||
.temp_file_name = VDSO__TEMP_FILE_NAME,
|
||||
.dso_name = DSO__NAME_VDSO,
|
||||
},
|
||||
};
|
||||
|
||||
return memdup(&vdso_info_init, sizeof(vdso_info_init));
|
||||
}
|
||||
|
||||
static int find_vdso_map(void **start, void **end)
|
||||
{
|
||||
@ -48,7 +71,7 @@ static int find_vdso_map(void **start, void **end)
|
||||
return !found;
|
||||
}
|
||||
|
||||
static char *get_file(void)
|
||||
static char *get_file(struct vdso_file *vdso_file)
|
||||
{
|
||||
char *vdso = NULL;
|
||||
char *buf = NULL;
|
||||
@ -56,10 +79,10 @@ static char *get_file(void)
|
||||
size_t size;
|
||||
int fd;
|
||||
|
||||
if (vdso_found)
|
||||
return vdso_file;
|
||||
if (vdso_file->found)
|
||||
return vdso_file->temp_file_name;
|
||||
|
||||
if (find_vdso_map(&start, &end))
|
||||
if (vdso_file->error || find_vdso_map(&start, &end))
|
||||
return NULL;
|
||||
|
||||
size = end - start;
|
||||
@ -68,45 +91,78 @@ static char *get_file(void)
|
||||
if (!buf)
|
||||
return NULL;
|
||||
|
||||
fd = mkstemp(vdso_file);
|
||||
fd = mkstemp(vdso_file->temp_file_name);
|
||||
if (fd < 0)
|
||||
goto out;
|
||||
|
||||
if (size == (size_t) write(fd, buf, size))
|
||||
vdso = vdso_file;
|
||||
vdso = vdso_file->temp_file_name;
|
||||
|
||||
close(fd);
|
||||
|
||||
out:
|
||||
free(buf);
|
||||
|
||||
vdso_found = (vdso != NULL);
|
||||
vdso_file->found = (vdso != NULL);
|
||||
vdso_file->error = !vdso_file->found;
|
||||
return vdso;
|
||||
}
|
||||
|
||||
void vdso__exit(void)
|
||||
void vdso__exit(struct machine *machine)
|
||||
{
|
||||
if (vdso_found)
|
||||
unlink(vdso_file);
|
||||
struct vdso_info *vdso_info = machine->vdso_info;
|
||||
|
||||
if (!vdso_info)
|
||||
return;
|
||||
|
||||
if (vdso_info->vdso.found)
|
||||
unlink(vdso_info->vdso.temp_file_name);
|
||||
|
||||
zfree(&machine->vdso_info);
|
||||
}
|
||||
|
||||
struct dso *vdso__dso_findnew(struct list_head *head)
|
||||
static struct dso *vdso__new(struct machine *machine, const char *short_name,
|
||||
const char *long_name)
|
||||
{
|
||||
struct dso *dso = dsos__find(head, VDSO__MAP_NAME, true);
|
||||
struct dso *dso;
|
||||
|
||||
if (!dso) {
|
||||
char *file;
|
||||
|
||||
file = get_file();
|
||||
if (!file)
|
||||
return NULL;
|
||||
|
||||
dso = dso__new(VDSO__MAP_NAME);
|
||||
if (dso != NULL) {
|
||||
dsos__add(head, dso);
|
||||
dso__set_long_name(dso, file, false);
|
||||
}
|
||||
dso = dso__new(short_name);
|
||||
if (dso != NULL) {
|
||||
dsos__add(&machine->user_dsos, dso);
|
||||
dso__set_long_name(dso, long_name, false);
|
||||
}
|
||||
|
||||
return dso;
|
||||
}
|
||||
|
||||
struct dso *vdso__dso_findnew(struct machine *machine,
|
||||
struct thread *thread __maybe_unused)
|
||||
{
|
||||
struct vdso_info *vdso_info;
|
||||
struct dso *dso;
|
||||
|
||||
if (!machine->vdso_info)
|
||||
machine->vdso_info = vdso_info__new();
|
||||
|
||||
vdso_info = machine->vdso_info;
|
||||
if (!vdso_info)
|
||||
return NULL;
|
||||
|
||||
dso = dsos__find(&machine->user_dsos, DSO__NAME_VDSO, true);
|
||||
if (!dso) {
|
||||
char *file;
|
||||
|
||||
file = get_file(&vdso_info->vdso);
|
||||
if (!file)
|
||||
return NULL;
|
||||
|
||||
dso = vdso__new(machine, DSO__NAME_VDSO, file);
|
||||
}
|
||||
|
||||
return dso;
|
||||
}
|
||||
|
||||
bool dso__is_vdso(struct dso *dso)
|
||||
{
|
||||
return !strcmp(dso->short_name, DSO__NAME_VDSO);
|
||||
}
|
||||
|
@ -7,12 +7,21 @@
|
||||
|
||||
#define VDSO__MAP_NAME "[vdso]"
|
||||
|
||||
#define DSO__NAME_VDSO "[vdso]"
|
||||
|
||||
static inline bool is_vdso_map(const char *filename)
|
||||
{
|
||||
return !strcmp(filename, VDSO__MAP_NAME);
|
||||
}
|
||||
|
||||
struct dso *vdso__dso_findnew(struct list_head *head);
|
||||
void vdso__exit(void);
|
||||
struct dso;
|
||||
|
||||
bool dso__is_vdso(struct dso *dso);
|
||||
|
||||
struct machine;
|
||||
struct thread;
|
||||
|
||||
struct dso *vdso__dso_findnew(struct machine *machine, struct thread *thread);
|
||||
void vdso__exit(struct machine *machine);
|
||||
|
||||
#endif /* __PERF_VDSO__ */
|
||||
|
Loading…
Reference in New Issue
Block a user