|
@@ -408,55 +408,6 @@ static int thread__set_comm_adjust(struct thread *self, const char *comm)
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
-
|
|
|
|
-static struct symbol *
|
|
|
|
-resolve_symbol(struct thread *thread, struct map **mapp, u64 *ipp)
|
|
|
|
-{
|
|
|
|
- struct map *map = mapp ? *mapp : NULL;
|
|
|
|
- u64 ip = *ipp;
|
|
|
|
-
|
|
|
|
- if (map)
|
|
|
|
- goto got_map;
|
|
|
|
-
|
|
|
|
- if (!thread)
|
|
|
|
- return NULL;
|
|
|
|
-
|
|
|
|
- map = thread__find_map(thread, MAP__FUNCTION, ip);
|
|
|
|
- if (map != NULL) {
|
|
|
|
- /*
|
|
|
|
- * We have to do this here as we may have a dso
|
|
|
|
- * with no symbol hit that has a name longer than
|
|
|
|
- * the ones with symbols sampled.
|
|
|
|
- */
|
|
|
|
- if (!sort_dso.elide && !map->dso->slen_calculated)
|
|
|
|
- dso__calc_col_width(map->dso);
|
|
|
|
-
|
|
|
|
- if (mapp)
|
|
|
|
- *mapp = map;
|
|
|
|
-got_map:
|
|
|
|
- ip = map->map_ip(map, ip);
|
|
|
|
- } else {
|
|
|
|
- /*
|
|
|
|
- * If this is outside of all known maps,
|
|
|
|
- * and is a negative address, try to look it
|
|
|
|
- * up in the kernel dso, as it might be a
|
|
|
|
- * vsyscall or vdso (which executes in user-mode).
|
|
|
|
- *
|
|
|
|
- * XXX This is nasty, we should have a symbol list in
|
|
|
|
- * the "[vdso]" dso, but for now lets use the old
|
|
|
|
- * trick of looking in the whole kernel symbol list.
|
|
|
|
- */
|
|
|
|
- if ((long long)ip < 0)
|
|
|
|
- return kernel_maps__find_function(ip, mapp, NULL);
|
|
|
|
- }
|
|
|
|
- dump_printf(" ...... dso: %s\n",
|
|
|
|
- map ? map->dso->long_name : "<not found>");
|
|
|
|
- dump_printf(" ...... map: %Lx -> %Lx\n", *ipp, ip);
|
|
|
|
- *ipp = ip;
|
|
|
|
-
|
|
|
|
- return map ? map__find_symbol(map, ip, NULL) : NULL;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
static int call__match(struct symbol *sym)
|
|
static int call__match(struct symbol *sym)
|
|
{
|
|
{
|
|
if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0))
|
|
if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0))
|
|
@@ -469,7 +420,7 @@ static struct symbol **resolve_callchain(struct thread *thread,
|
|
struct ip_callchain *chain,
|
|
struct ip_callchain *chain,
|
|
struct symbol **parent)
|
|
struct symbol **parent)
|
|
{
|
|
{
|
|
- u64 context = PERF_CONTEXT_MAX;
|
|
|
|
|
|
+ u8 cpumode = PERF_RECORD_MISC_USER;
|
|
struct symbol **syms = NULL;
|
|
struct symbol **syms = NULL;
|
|
unsigned int i;
|
|
unsigned int i;
|
|
|
|
|
|
@@ -483,30 +434,31 @@ static struct symbol **resolve_callchain(struct thread *thread,
|
|
|
|
|
|
for (i = 0; i < chain->nr; i++) {
|
|
for (i = 0; i < chain->nr; i++) {
|
|
u64 ip = chain->ips[i];
|
|
u64 ip = chain->ips[i];
|
|
- struct symbol *sym = NULL;
|
|
|
|
|
|
+ struct addr_location al;
|
|
|
|
|
|
if (ip >= PERF_CONTEXT_MAX) {
|
|
if (ip >= PERF_CONTEXT_MAX) {
|
|
- context = ip;
|
|
|
|
|
|
+ switch (ip) {
|
|
|
|
+ case PERF_CONTEXT_HV:
|
|
|
|
+ cpumode = PERF_RECORD_MISC_HYPERVISOR; break;
|
|
|
|
+ case PERF_CONTEXT_KERNEL:
|
|
|
|
+ cpumode = PERF_RECORD_MISC_KERNEL; break;
|
|
|
|
+ case PERF_CONTEXT_USER:
|
|
|
|
+ cpumode = PERF_RECORD_MISC_USER; break;
|
|
|
|
+ default:
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
continue;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
|
|
- switch (context) {
|
|
|
|
- case PERF_CONTEXT_HV:
|
|
|
|
- break;
|
|
|
|
- case PERF_CONTEXT_KERNEL:
|
|
|
|
- sym = kernel_maps__find_function(ip, NULL, NULL);
|
|
|
|
- break;
|
|
|
|
- default:
|
|
|
|
- sym = resolve_symbol(thread, NULL, &ip);
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (sym) {
|
|
|
|
- if (sort__has_parent && !*parent && call__match(sym))
|
|
|
|
- *parent = sym;
|
|
|
|
|
|
+ thread__find_addr_location(thread, cpumode, MAP__FUNCTION,
|
|
|
|
+ ip, &al, NULL);
|
|
|
|
+ if (al.sym != NULL) {
|
|
|
|
+ if (sort__has_parent && !*parent &&
|
|
|
|
+ call__match(al.sym))
|
|
|
|
+ *parent = al.sym;
|
|
if (!callchain)
|
|
if (!callchain)
|
|
break;
|
|
break;
|
|
- syms[i] = sym;
|
|
|
|
|
|
+ syms[i] = al.sym;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -517,20 +469,17 @@ static struct symbol **resolve_callchain(struct thread *thread,
|
|
* collect histogram counts
|
|
* collect histogram counts
|
|
*/
|
|
*/
|
|
|
|
|
|
-static int
|
|
|
|
-hist_entry__add(struct thread *thread, struct map *map,
|
|
|
|
- struct symbol *sym, u64 ip, struct ip_callchain *chain,
|
|
|
|
- char level, u64 count)
|
|
|
|
|
|
+static int hist_entry__add(struct addr_location *al,
|
|
|
|
+ struct ip_callchain *chain, u64 count)
|
|
{
|
|
{
|
|
struct symbol **syms = NULL, *parent = NULL;
|
|
struct symbol **syms = NULL, *parent = NULL;
|
|
bool hit;
|
|
bool hit;
|
|
struct hist_entry *he;
|
|
struct hist_entry *he;
|
|
|
|
|
|
if ((sort__has_parent || callchain) && chain)
|
|
if ((sort__has_parent || callchain) && chain)
|
|
- syms = resolve_callchain(thread, chain, &parent);
|
|
|
|
|
|
+ syms = resolve_callchain(al->thread, chain, &parent);
|
|
|
|
|
|
- he = __hist_entry__add(thread, map, sym, parent,
|
|
|
|
- ip, count, level, &hit);
|
|
|
|
|
|
+ he = __hist_entry__add(al, parent, count, &hit);
|
|
if (he == NULL)
|
|
if (he == NULL)
|
|
return -ENOMEM;
|
|
return -ENOMEM;
|
|
|
|
|
|
@@ -656,14 +605,12 @@ static int validate_chain(struct ip_callchain *chain, event_t *event)
|
|
|
|
|
|
static int process_sample_event(event_t *event)
|
|
static int process_sample_event(event_t *event)
|
|
{
|
|
{
|
|
- char level;
|
|
|
|
- struct symbol *sym = NULL;
|
|
|
|
u64 ip = event->ip.ip;
|
|
u64 ip = event->ip.ip;
|
|
u64 period = 1;
|
|
u64 period = 1;
|
|
- struct map *map = NULL;
|
|
|
|
void *more_data = event->ip.__more_data;
|
|
void *more_data = event->ip.__more_data;
|
|
struct ip_callchain *chain = NULL;
|
|
struct ip_callchain *chain = NULL;
|
|
int cpumode;
|
|
int cpumode;
|
|
|
|
+ struct addr_location al;
|
|
struct thread *thread = threads__findnew(event->ip.pid);
|
|
struct thread *thread = threads__findnew(event->ip.pid);
|
|
|
|
|
|
if (sample_type & PERF_SAMPLE_PERIOD) {
|
|
if (sample_type & PERF_SAMPLE_PERIOD) {
|
|
@@ -709,32 +656,26 @@ static int process_sample_event(event_t *event)
|
|
|
|
|
|
cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
|
|
cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
|
|
|
|
|
|
- if (cpumode == PERF_RECORD_MISC_KERNEL) {
|
|
|
|
- level = 'k';
|
|
|
|
- sym = kernel_maps__find_function(ip, &map, NULL);
|
|
|
|
- dump_printf(" ...... dso: %s\n",
|
|
|
|
- map ? map->dso->long_name : "<not found>");
|
|
|
|
- } else if (cpumode == PERF_RECORD_MISC_USER) {
|
|
|
|
- level = '.';
|
|
|
|
- sym = resolve_symbol(thread, &map, &ip);
|
|
|
|
-
|
|
|
|
- } else {
|
|
|
|
- level = 'H';
|
|
|
|
- dump_printf(" ...... dso: [hypervisor]\n");
|
|
|
|
- }
|
|
|
|
|
|
+ thread__find_addr_location(thread, cpumode,
|
|
|
|
+ MAP__FUNCTION, ip, &al, NULL);
|
|
|
|
+ /*
|
|
|
|
+ * We have to do this here as we may have a dso with no symbol hit that
|
|
|
|
+ * has a name longer than the ones with symbols sampled.
|
|
|
|
+ */
|
|
|
|
+ if (al.map && !sort_dso.elide && !al.map->dso->slen_calculated)
|
|
|
|
+ dso__calc_col_width(al.map->dso);
|
|
|
|
|
|
if (dso_list &&
|
|
if (dso_list &&
|
|
- (!map || !map->dso ||
|
|
|
|
- !(strlist__has_entry(dso_list, map->dso->short_name) ||
|
|
|
|
- (map->dso->short_name != map->dso->long_name &&
|
|
|
|
- strlist__has_entry(dso_list, map->dso->long_name)))))
|
|
|
|
|
|
+ (!al.map || !al.map->dso ||
|
|
|
|
+ !(strlist__has_entry(dso_list, al.map->dso->short_name) ||
|
|
|
|
+ (al.map->dso->short_name != al.map->dso->long_name &&
|
|
|
|
+ strlist__has_entry(dso_list, al.map->dso->long_name)))))
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
- if (sym_list && sym && !strlist__has_entry(sym_list, sym->name))
|
|
|
|
|
|
+ if (sym_list && al.sym && !strlist__has_entry(sym_list, al.sym->name))
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
- if (hist_entry__add(thread, map, sym, ip,
|
|
|
|
- chain, level, period)) {
|
|
|
|
|
|
+ if (hist_entry__add(&al, chain, period)) {
|
|
pr_debug("problem incrementing symbol count, skipping event\n");
|
|
pr_debug("problem incrementing symbol count, skipping event\n");
|
|
return -1;
|
|
return -1;
|
|
}
|
|
}
|