perf/core improvements and fixes:
perf stat: (Jiri Olsa) - Display time in precision based on std deviation - Add --table option to display time of each run - Display length strings of each run for --table option perf buildid-cache: (Ravi Bangoria) - Add --list and --purge-all options perf test: (Hendrik Brueckner) - Let 'perf test list' display subtests Core libraries: - Remove the splitting of maps into MAP__FUNCTION and MAP__VARIABLE. It isn't needed, adds complexity, so remove this split in a very granular fashion using better ways of detecting if a map is executable, using map->prot, etc. More is needed to further untangle map aspects from DSO ones and also to have arch specific stuff better isolated. (Arnaldo Carvalho de Melo) - Fix spelling mistake: "builid" -> "buildid" in a jitdump error message (Colin Ian King) Build system: (Jiri Olsa) - Add support to check 2 independent files in check-headers.sh Documentation: (Takashi Iwai) - Support for asciidoctor, since 'asciidoc' wasn't so far ported to python3 and distros are ditching python2 Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEELb9bqkb7Te0zijNb1lAW81NSqkAFAlrpzUMACgkQ1lAW81NS qkA0rhAAtIOoKqapKp0vuSMQlGYvTqleUrY9PJg4JBzgcHJUJqsS3mVinSwpNEfh RpFV2Ttrwe5RmqE8IdDtHn1C9OvFLMtLMA1qu1Os1yaJbOTEjzKfWOG+thNeN3rM ogcUNasGygyR1ONdya9RiRG1E6Bn1Z01vNc8EXJYoLuGTswcPVmM8Nx/hLChM7qh qISBR3l04gl4H66NSd1fQ4nNDcPMNxWrBlKr7SWO+tCw342KqnEylg9u77sDs8U0 nBtYZkemBWzRrKoVSQ68DJ0KYrkMlOIO/86f0gwC+8Jlv0d7iFFX/rXOcR5tXHmT lUvRA74njZCReiUGwOJh9evzZ16NvIfYtAbQgUq2oR6KAEnN/5gHIc1XkCmzE1G4 zXC55WsWbN1nfbQk0/58Cnn+ZaMyBt2VnuAAxIeJx7pH+SYTdjohFsRkumLEoZlh +nHZ6/kf29dbxDtcH/PksoMRlDV3yJi2lnCwAid2tG4irT27ilB04UpL/xU9EED7 ZcHbBf3Y2vEXUGb/5GACdMy8H3L0d1GnRhv9pih8swCkhGRbiAYnX+ri8JtwbNf8 lmzUdt9GIY9FKtQOedoKIa2bvVQ0juPr4M3G7QgJn3iK/f7T0F9xMMWWR5gO6xai h94p+7uVGuzD+zIQU5xeb/QZyUq0XU9IGZZ447nOk7mh7jXNcrg= =n34x -----END PGP SIGNATURE----- Merge tag 'perf-core-for-mingo-4.18-20180502' 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: perf stat: (Jiri Olsa) - Display time in precision based on std deviation - Add --table option to display time of each run - Display length strings of each run for --table option perf buildid-cache: (Ravi Bangoria) - Add --list and --purge-all options perf test: (Hendrik Brueckner) - Let 'perf test list' display subtests Core libraries: - Remove the splitting of maps into MAP__FUNCTION and MAP__VARIABLE. It isn't needed, adds complexity, so remove this split in a very granular fashion using better ways of detecting if a map is executable, using map->prot, etc. More is needed to further untangle map aspects from DSO ones and also to have arch specific stuff better isolated. (Arnaldo Carvalho de Melo) - Fix spelling mistake: "builid" -> "buildid" in a jitdump error message (Colin Ian King) Build system: (Jiri Olsa) - Add support to check 2 independent files in check-headers.sh Documentation: (Takashi Iwai) - Support for asciidoctor, since 'asciidoc' wasn't so far ported to python3 and distros are ditching python2 Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
commit
eaeb1f4d89
@ -10,6 +10,12 @@ u8 kallsyms2elf_type(char type)
|
||||
return (type == 't' || type == 'w') ? STT_FUNC : STT_OBJECT;
|
||||
}
|
||||
|
||||
bool kallsyms__is_function(char symbol_type)
|
||||
{
|
||||
symbol_type = toupper(symbol_type);
|
||||
return symbol_type == 'T' || symbol_type == 'W';
|
||||
}
|
||||
|
||||
int kallsyms__parse(const char *filename, void *arg,
|
||||
int (*process_symbol)(void *arg, const char *name,
|
||||
char type, u64 start))
|
||||
|
@ -20,6 +20,8 @@ static inline u8 kallsyms2elf_binding(char type)
|
||||
|
||||
u8 kallsyms2elf_type(char type);
|
||||
|
||||
bool kallsyms__is_function(char symbol_type);
|
||||
|
||||
int kallsyms__parse(const char *filename, void *arg,
|
||||
int (*process_symbol)(void *arg, const char *name,
|
||||
char type, u64 start));
|
||||
|
@ -47,7 +47,8 @@ man5dir=$(mandir)/man5
|
||||
man7dir=$(mandir)/man7
|
||||
|
||||
ASCIIDOC=asciidoc
|
||||
ASCIIDOC_EXTRA = --unsafe
|
||||
ASCIIDOC_EXTRA = --unsafe -f asciidoc.conf
|
||||
ASCIIDOC_HTML = xhtml11
|
||||
MANPAGE_XSL = manpage-normal.xsl
|
||||
XMLTO_EXTRA =
|
||||
INSTALL?=install
|
||||
@ -55,6 +56,14 @@ RM ?= rm -f
|
||||
DOC_REF = origin/man
|
||||
HTML_REF = origin/html
|
||||
|
||||
ifdef USE_ASCIIDOCTOR
|
||||
ASCIIDOC = asciidoctor
|
||||
ASCIIDOC_EXTRA = -a compat-mode
|
||||
ASCIIDOC_EXTRA += -I. -rasciidoctor-extensions
|
||||
ASCIIDOC_EXTRA += -a mansource="perf" -a manmanual="perf Manual"
|
||||
ASCIIDOC_HTML = xhtml5
|
||||
endif
|
||||
|
||||
infodir?=$(prefix)/share/info
|
||||
MAKEINFO=makeinfo
|
||||
INSTALL_INFO=install-info
|
||||
@ -73,10 +82,12 @@ ifeq ($(_tmp_tool_path),)
|
||||
missing_tools = $(ASCIIDOC)
|
||||
endif
|
||||
|
||||
ifndef USE_ASCIIDOCTOR
|
||||
_tmp_tool_path := $(call get-executable,$(XMLTO))
|
||||
ifeq ($(_tmp_tool_path),)
|
||||
missing_tools += $(XMLTO)
|
||||
endif
|
||||
endif
|
||||
|
||||
#
|
||||
# For asciidoc ...
|
||||
@ -264,17 +275,25 @@ clean:
|
||||
|
||||
$(MAN_HTML): $(OUTPUT)%.html : %.txt
|
||||
$(QUIET_ASCIIDOC)$(RM) $@+ $@ && \
|
||||
$(ASCIIDOC) -b xhtml11 -d manpage -f asciidoc.conf \
|
||||
$(ASCIIDOC) -b $(ASCIIDOC_HTML) -d manpage \
|
||||
$(ASCIIDOC_EXTRA) -aperf_version=$(PERF_VERSION) -o $@+ $< && \
|
||||
mv $@+ $@
|
||||
|
||||
ifdef USE_ASCIIDOCTOR
|
||||
$(OUTPUT)%.1 $(OUTPUT)%.5 $(OUTPUT)%.7 : $(OUTPUT)%.txt
|
||||
$(QUIET_ASCIIDOC)$(RM) $@+ $@ && \
|
||||
$(ASCIIDOC) -b manpage -d manpage \
|
||||
$(ASCIIDOC_EXTRA) -aperf_version=$(PERF_VERSION) -o $@+ $< && \
|
||||
mv $@+ $@
|
||||
endif
|
||||
|
||||
$(OUTPUT)%.1 $(OUTPUT)%.5 $(OUTPUT)%.7 : $(OUTPUT)%.xml
|
||||
$(QUIET_XMLTO)$(RM) $@ && \
|
||||
$(XMLTO) -o $(OUTPUT). -m $(MANPAGE_XSL) $(XMLTO_EXTRA) man $<
|
||||
|
||||
$(OUTPUT)%.xml : %.txt
|
||||
$(QUIET_ASCIIDOC)$(RM) $@+ $@ && \
|
||||
$(ASCIIDOC) -b docbook -d manpage -f asciidoc.conf \
|
||||
$(ASCIIDOC) -b docbook -d manpage \
|
||||
$(ASCIIDOC_EXTRA) -aperf_version=$(PERF_VERSION) -o $@+ $< && \
|
||||
mv $@+ $@
|
||||
|
||||
@ -321,13 +340,13 @@ howto-index.txt: howto-index.sh $(wildcard howto/*.txt)
|
||||
mv $@+ $@
|
||||
|
||||
$(patsubst %,%.html,$(ARTICLES)) : %.html : %.txt
|
||||
$(QUIET_ASCIIDOC)$(ASCIIDOC) -b xhtml11 $*.txt
|
||||
$(QUIET_ASCIIDOC)$(ASCIIDOC) -b $(ASCIIDOC_HTML) $*.txt
|
||||
|
||||
WEBDOC_DEST = /pub/software/tools/perf/docs
|
||||
|
||||
$(patsubst %.txt,%.html,$(wildcard howto/*.txt)): %.html : %.txt
|
||||
$(QUIET_ASCIIDOC)$(RM) $@+ $@ && \
|
||||
sed -e '1,/^$$/d' $< | $(ASCIIDOC) -b xhtml11 - >$@+ && \
|
||||
sed -e '1,/^$$/d' $< | $(ASCIIDOC) -b $(ASCIIDOC_HTML) - >$@+ && \
|
||||
mv $@+ $@
|
||||
|
||||
# UNIMPLEMENTED
|
||||
|
29
tools/perf/Documentation/asciidoctor-extensions.rb
Normal file
29
tools/perf/Documentation/asciidoctor-extensions.rb
Normal file
@ -0,0 +1,29 @@
|
||||
require 'asciidoctor'
|
||||
require 'asciidoctor/extensions'
|
||||
|
||||
module Perf
|
||||
module Documentation
|
||||
class LinkPerfProcessor < Asciidoctor::Extensions::InlineMacroProcessor
|
||||
use_dsl
|
||||
|
||||
named :chrome
|
||||
|
||||
def process(parent, target, attrs)
|
||||
if parent.document.basebackend? 'html'
|
||||
%(<a href="#{target}.html">#{target}(#{attrs[1]})</a>\n)
|
||||
elsif parent.document.basebackend? 'manpage'
|
||||
"#{target}(#{attrs[1]})"
|
||||
elsif parent.document.basebackend? 'docbook'
|
||||
"<citerefentry>\n" \
|
||||
"<refentrytitle>#{target}</refentrytitle>" \
|
||||
"<manvolnum>#{attrs[1]}</manvolnum>\n" \
|
||||
"</citerefentry>\n"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Asciidoctor::Extensions.register do
|
||||
inline_macro Perf::Documentation::LinkPerfProcessor, :linkperf
|
||||
end
|
@ -48,6 +48,9 @@ OPTIONS
|
||||
--purge=::
|
||||
Purge all cached binaries including older caches which have specified
|
||||
path from the cache.
|
||||
-P::
|
||||
--purge-all::
|
||||
Purge all cached binaries. This will flush out entire cache.
|
||||
-M::
|
||||
--missing=::
|
||||
List missing build ids in the cache for the specified file.
|
||||
@ -59,7 +62,9 @@ OPTIONS
|
||||
exactly same build-id, that is replaced by new one. It can be used
|
||||
to update kallsyms and kernel dso to vmlinux in order to support
|
||||
annotation.
|
||||
|
||||
-l::
|
||||
--list::
|
||||
List all valid binaries from cache.
|
||||
-v::
|
||||
--verbose::
|
||||
Be more verbose.
|
||||
|
@ -116,6 +116,22 @@ Do not aggregate counts across all monitored CPUs.
|
||||
print counts using a CSV-style output to make it easy to import directly into
|
||||
spreadsheets. Columns are separated by the string specified in SEP.
|
||||
|
||||
--table:: Display time for each run (-r option), in a table format, e.g.:
|
||||
|
||||
$ perf stat --null -r 5 --table perf bench sched pipe
|
||||
|
||||
Performance counter stats for 'perf bench sched pipe' (5 runs):
|
||||
|
||||
# Table of individual measurements:
|
||||
5.189 (-0.293) #
|
||||
5.189 (-0.294) #
|
||||
5.186 (-0.296) #
|
||||
5.663 (+0.181) ##
|
||||
6.186 (+0.703) ####
|
||||
|
||||
# Final result:
|
||||
5.483 +- 0.198 seconds time elapsed ( +- 3.62% )
|
||||
|
||||
-G name::
|
||||
--cgroup name::
|
||||
monitor only in the container (cgroup) called "name". This option is available only
|
||||
|
@ -25,7 +25,7 @@ static int sample_ustack(struct perf_sample *sample,
|
||||
|
||||
sp = (unsigned long) regs[PERF_REG_ARM_SP];
|
||||
|
||||
map = map_groups__find(thread->mg, MAP__VARIABLE, (u64) sp);
|
||||
map = map_groups__find(thread->mg, (u64)sp);
|
||||
if (!map) {
|
||||
pr_debug("failed to get stack map\n");
|
||||
free(buf);
|
||||
|
@ -25,7 +25,7 @@ static int sample_ustack(struct perf_sample *sample,
|
||||
|
||||
sp = (unsigned long) regs[PERF_REG_ARM64_SP];
|
||||
|
||||
map = map_groups__find(thread->mg, MAP__VARIABLE, (u64) sp);
|
||||
map = map_groups__find(thread->mg, (u64)sp);
|
||||
if (!map) {
|
||||
pr_debug("failed to get stack map\n");
|
||||
free(buf);
|
||||
|
@ -26,7 +26,7 @@ static int sample_ustack(struct perf_sample *sample,
|
||||
|
||||
sp = (unsigned long) regs[PERF_REG_POWERPC_R1];
|
||||
|
||||
map = map_groups__find(thread->mg, MAP__VARIABLE, (u64) sp);
|
||||
map = map_groups__find(thread->mg, (u64)sp);
|
||||
if (!map) {
|
||||
pr_debug("failed to get stack map\n");
|
||||
free(buf);
|
||||
|
@ -248,8 +248,7 @@ int arch_skip_callchain_idx(struct thread *thread, struct ip_callchain *chain)
|
||||
|
||||
ip = chain->ips[2];
|
||||
|
||||
thread__find_addr_location(thread, PERF_RECORD_MISC_USER,
|
||||
MAP__FUNCTION, ip, &al);
|
||||
thread__find_symbol(thread, PERF_RECORD_MISC_USER, ip, &al);
|
||||
|
||||
if (al.map)
|
||||
dso = al.map->dso;
|
||||
|
@ -26,7 +26,7 @@ static int sample_ustack(struct perf_sample *sample,
|
||||
|
||||
sp = (unsigned long) regs[PERF_REG_X86_SP];
|
||||
|
||||
map = map_groups__find(thread->mg, MAP__VARIABLE, (u64) sp);
|
||||
map = map_groups__find(thread->mg, (u64)sp);
|
||||
if (!map) {
|
||||
pr_debug("failed to get stack map\n");
|
||||
free(buf);
|
||||
|
@ -228,7 +228,7 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel,
|
||||
*/
|
||||
if (al->sym != NULL) {
|
||||
rb_erase(&al->sym->rb_node,
|
||||
&al->map->dso->symbols[al->map->type]);
|
||||
&al->map->dso->symbols);
|
||||
symbol__delete(al->sym);
|
||||
dso__reset_find_symbol_cache(al->map->dso);
|
||||
}
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "util/session.h"
|
||||
#include "util/symbol.h"
|
||||
#include "util/time-utils.h"
|
||||
#include "util/probe-file.h"
|
||||
|
||||
static int build_id_cache__kcore_buildid(const char *proc_dir, char *sbuildid)
|
||||
{
|
||||
@ -239,6 +240,34 @@ out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int build_id_cache__purge_all(void)
|
||||
{
|
||||
struct strlist *list;
|
||||
struct str_node *pos;
|
||||
int err = 0;
|
||||
char *buf;
|
||||
|
||||
list = build_id_cache__list_all(false);
|
||||
if (!list) {
|
||||
pr_debug("Failed to get buildids: -%d\n", errno);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
strlist__for_each_entry(pos, list) {
|
||||
buf = build_id_cache__origname(pos->s);
|
||||
err = build_id_cache__remove_s(pos->s);
|
||||
pr_debug("Removing %s (%s): %s\n", buf, pos->s,
|
||||
err ? "FAIL" : "Ok");
|
||||
free(buf);
|
||||
if (err)
|
||||
break;
|
||||
}
|
||||
strlist__delete(list);
|
||||
|
||||
pr_debug("Purged all: %s\n", err ? "FAIL" : "Ok");
|
||||
return err;
|
||||
}
|
||||
|
||||
static bool dso__missing_buildid_cache(struct dso *dso, int parm __maybe_unused)
|
||||
{
|
||||
char filename[PATH_MAX];
|
||||
@ -297,6 +326,26 @@ static int build_id_cache__update_file(const char *filename, struct nsinfo *nsi)
|
||||
return err;
|
||||
}
|
||||
|
||||
static int build_id_cache__show_all(void)
|
||||
{
|
||||
struct strlist *bidlist;
|
||||
struct str_node *nd;
|
||||
char *buf;
|
||||
|
||||
bidlist = build_id_cache__list_all(true);
|
||||
if (!bidlist) {
|
||||
pr_debug("Failed to get buildids: -%d\n", errno);
|
||||
return -1;
|
||||
}
|
||||
strlist__for_each_entry(nd, bidlist) {
|
||||
buf = build_id_cache__origname(nd->s);
|
||||
fprintf(stdout, "%s %s\n", nd->s, buf);
|
||||
free(buf);
|
||||
}
|
||||
strlist__delete(bidlist);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cmd_buildid_cache(int argc, const char **argv)
|
||||
{
|
||||
struct strlist *list;
|
||||
@ -304,6 +353,9 @@ int cmd_buildid_cache(int argc, const char **argv)
|
||||
int ret = 0;
|
||||
int ns_id = -1;
|
||||
bool force = false;
|
||||
bool list_files = false;
|
||||
bool opts_flag = false;
|
||||
bool purge_all = false;
|
||||
char const *add_name_list_str = NULL,
|
||||
*remove_name_list_str = NULL,
|
||||
*purge_name_list_str = NULL,
|
||||
@ -327,6 +379,8 @@ int cmd_buildid_cache(int argc, const char **argv)
|
||||
"file(s) to remove"),
|
||||
OPT_STRING('p', "purge", &purge_name_list_str, "file list",
|
||||
"file(s) to remove (remove old caches too)"),
|
||||
OPT_BOOLEAN('P', "purge-all", &purge_all, "purge all cached files"),
|
||||
OPT_BOOLEAN('l', "list", &list_files, "list all cached files"),
|
||||
OPT_STRING('M', "missing", &missing_filename, "file",
|
||||
"to find missing build ids in the cache"),
|
||||
OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
|
||||
@ -344,11 +398,20 @@ int cmd_buildid_cache(int argc, const char **argv)
|
||||
argc = parse_options(argc, argv, buildid_cache_options,
|
||||
buildid_cache_usage, 0);
|
||||
|
||||
if (argc || (!add_name_list_str && !kcore_filename &&
|
||||
!remove_name_list_str && !purge_name_list_str &&
|
||||
!missing_filename && !update_name_list_str))
|
||||
opts_flag = add_name_list_str || kcore_filename ||
|
||||
remove_name_list_str || purge_name_list_str ||
|
||||
missing_filename || update_name_list_str ||
|
||||
purge_all;
|
||||
|
||||
if (argc || !(list_files || opts_flag))
|
||||
usage_with_options(buildid_cache_usage, buildid_cache_options);
|
||||
|
||||
/* -l is exclusive. It can not be used with other options. */
|
||||
if (list_files && opts_flag) {
|
||||
usage_with_options_msg(buildid_cache_usage,
|
||||
buildid_cache_options, "-l is exclusive.\n");
|
||||
}
|
||||
|
||||
if (ns_id > 0)
|
||||
nsi = nsinfo__new(ns_id);
|
||||
|
||||
@ -366,6 +429,11 @@ int cmd_buildid_cache(int argc, const char **argv)
|
||||
|
||||
setup_pager();
|
||||
|
||||
if (list_files) {
|
||||
ret = build_id_cache__show_all();
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (add_name_list_str) {
|
||||
list = strlist__new(add_name_list_str, NULL);
|
||||
if (list) {
|
||||
@ -420,6 +488,9 @@ int cmd_buildid_cache(int argc, const char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
if (purge_all)
|
||||
ret = build_id_cache__purge_all();
|
||||
|
||||
if (missing_filename)
|
||||
ret = build_id_cache__fprintf_missing(session, stdout);
|
||||
|
||||
|
@ -440,9 +440,7 @@ static int perf_event__inject_buildid(struct perf_tool *tool,
|
||||
goto repipe;
|
||||
}
|
||||
|
||||
thread__find_addr_map(thread, sample->cpumode, MAP__FUNCTION, sample->ip, &al);
|
||||
|
||||
if (al.map != NULL) {
|
||||
if (thread__find_map(thread, sample->cpumode, sample->ip, &al)) {
|
||||
if (!al.map->dso->hit) {
|
||||
al.map->dso->hit = 1;
|
||||
if (map__load(al.map) >= 0) {
|
||||
|
@ -27,7 +27,7 @@ static int __cmd_kallsyms(int argc, const char **argv)
|
||||
|
||||
for (i = 0; i < argc; ++i) {
|
||||
struct map *map;
|
||||
struct symbol *symbol = machine__find_kernel_function_by_name(machine, argv[i], &map);
|
||||
struct symbol *symbol = machine__find_kernel_symbol_by_name(machine, argv[i], &map);
|
||||
|
||||
if (symbol == NULL) {
|
||||
printf("%s: not found\n", argv[i]);
|
||||
|
@ -1004,7 +1004,7 @@ static void __print_slab_result(struct rb_root *root,
|
||||
if (is_caller) {
|
||||
addr = data->call_site;
|
||||
if (!raw_ip)
|
||||
sym = machine__find_kernel_function(machine, addr, &map);
|
||||
sym = machine__find_kernel_symbol(machine, addr, &map);
|
||||
} else
|
||||
addr = data->ptr;
|
||||
|
||||
@ -1068,7 +1068,7 @@ static void __print_page_alloc_result(struct perf_session *session, int n_lines)
|
||||
char *caller = buf;
|
||||
|
||||
data = rb_entry(next, struct page_stat, node);
|
||||
sym = machine__find_kernel_function(machine, data->callsite, &map);
|
||||
sym = machine__find_kernel_symbol(machine, data->callsite, &map);
|
||||
if (sym)
|
||||
caller = sym->name;
|
||||
else
|
||||
@ -1110,7 +1110,7 @@ static void __print_page_caller_result(struct perf_session *session, int n_lines
|
||||
char *caller = buf;
|
||||
|
||||
data = rb_entry(next, struct page_stat, node);
|
||||
sym = machine__find_kernel_function(machine, data->callsite, &map);
|
||||
sym = machine__find_kernel_symbol(machine, data->callsite, &map);
|
||||
if (sym)
|
||||
caller = sym->name;
|
||||
else
|
||||
|
@ -523,12 +523,9 @@ static void report__warn_kptr_restrict(const struct report *rep)
|
||||
"As no suitable kallsyms nor vmlinux was found, kernel samples\n"
|
||||
"can't be resolved.";
|
||||
|
||||
if (kernel_map) {
|
||||
const struct dso *kdso = kernel_map->dso;
|
||||
if (!RB_EMPTY_ROOT(&kdso->symbols[MAP__FUNCTION])) {
|
||||
desc = "If some relocation was applied (e.g. "
|
||||
"kexec) symbols may be misresolved.";
|
||||
}
|
||||
if (kernel_map && map__has_symbols(kernel_map)) {
|
||||
desc = "If some relocation was applied (e.g. "
|
||||
"kexec) symbols may be misresolved.";
|
||||
}
|
||||
|
||||
ui__warning(
|
||||
@ -718,10 +715,7 @@ static size_t maps__fprintf_task(struct maps *maps, int indent, FILE *fp)
|
||||
|
||||
static int map_groups__fprintf_task(struct map_groups *mg, int indent, FILE *fp)
|
||||
{
|
||||
int printed = 0, i;
|
||||
for (i = 0; i < MAP__NR_TYPES; ++i)
|
||||
printed += maps__fprintf_task(&mg->maps[i], indent, fp);
|
||||
return printed;
|
||||
return maps__fprintf_task(&mg->maps, indent, fp);
|
||||
}
|
||||
|
||||
static void task__print_level(struct task *task, FILE *fp, int level)
|
||||
|
@ -717,8 +717,8 @@ static int perf_sample__fprintf_brstack(struct perf_sample *sample,
|
||||
if (PRINT_FIELD(DSO)) {
|
||||
memset(&alf, 0, sizeof(alf));
|
||||
memset(&alt, 0, sizeof(alt));
|
||||
thread__find_addr_map(thread, sample->cpumode, MAP__FUNCTION, from, &alf);
|
||||
thread__find_addr_map(thread, sample->cpumode, MAP__FUNCTION, to, &alt);
|
||||
thread__find_map(thread, sample->cpumode, from, &alf);
|
||||
thread__find_map(thread, sample->cpumode, to, &alt);
|
||||
}
|
||||
|
||||
printed += fprintf(fp, " 0x%"PRIx64, from);
|
||||
@ -764,13 +764,8 @@ static int perf_sample__fprintf_brstacksym(struct perf_sample *sample,
|
||||
from = br->entries[i].from;
|
||||
to = br->entries[i].to;
|
||||
|
||||
thread__find_addr_map(thread, sample->cpumode, MAP__FUNCTION, from, &alf);
|
||||
if (alf.map)
|
||||
alf.sym = map__find_symbol(alf.map, alf.addr);
|
||||
|
||||
thread__find_addr_map(thread, sample->cpumode, MAP__FUNCTION, to, &alt);
|
||||
if (alt.map)
|
||||
alt.sym = map__find_symbol(alt.map, alt.addr);
|
||||
thread__find_symbol(thread, sample->cpumode, from, &alf);
|
||||
thread__find_symbol(thread, sample->cpumode, to, &alt);
|
||||
|
||||
printed += symbol__fprintf_symname_offs(alf.sym, &alf, fp);
|
||||
if (PRINT_FIELD(DSO)) {
|
||||
@ -814,12 +809,12 @@ static int perf_sample__fprintf_brstackoff(struct perf_sample *sample,
|
||||
from = br->entries[i].from;
|
||||
to = br->entries[i].to;
|
||||
|
||||
thread__find_addr_map(thread, sample->cpumode, MAP__FUNCTION, from, &alf);
|
||||
if (alf.map && !alf.map->dso->adjust_symbols)
|
||||
if (thread__find_map(thread, sample->cpumode, from, &alf) &&
|
||||
!alf.map->dso->adjust_symbols)
|
||||
from = map__map_ip(alf.map, from);
|
||||
|
||||
thread__find_addr_map(thread, sample->cpumode, MAP__FUNCTION, to, &alt);
|
||||
if (alt.map && !alt.map->dso->adjust_symbols)
|
||||
if (thread__find_map(thread, sample->cpumode, to, &alt) &&
|
||||
!alt.map->dso->adjust_symbols)
|
||||
to = map__map_ip(alt.map, to);
|
||||
|
||||
printed += fprintf(fp, " 0x%"PRIx64, from);
|
||||
@ -882,8 +877,7 @@ static int grab_bb(u8 *buffer, u64 start, u64 end,
|
||||
return 0;
|
||||
}
|
||||
|
||||
thread__find_addr_map(thread, *cpumode, MAP__FUNCTION, start, &al);
|
||||
if (!al.map || !al.map->dso) {
|
||||
if (!thread__find_map(thread, *cpumode, start, &al) || !al.map->dso) {
|
||||
pr_debug("\tcannot resolve %" PRIx64 "-%" PRIx64 "\n", start, end);
|
||||
return 0;
|
||||
}
|
||||
@ -933,10 +927,8 @@ static int ip__fprintf_sym(uint64_t addr, struct thread *thread,
|
||||
|
||||
memset(&al, 0, sizeof(al));
|
||||
|
||||
thread__find_addr_map(thread, cpumode, MAP__FUNCTION, addr, &al);
|
||||
if (!al.map)
|
||||
thread__find_addr_map(thread, cpumode, MAP__VARIABLE,
|
||||
addr, &al);
|
||||
thread__find_map(thread, cpumode, addr, &al);
|
||||
|
||||
if ((*lastsym) && al.addr >= (*lastsym)->start && al.addr < (*lastsym)->end)
|
||||
return 0;
|
||||
|
||||
|
@ -164,6 +164,7 @@ static bool forever = false;
|
||||
static bool metric_only = false;
|
||||
static bool force_metric_only = false;
|
||||
static bool no_merge = false;
|
||||
static bool walltime_run_table = false;
|
||||
static struct timespec ref_time;
|
||||
static struct cpu_map *aggr_map;
|
||||
static aggr_get_id_t aggr_get_id;
|
||||
@ -173,6 +174,7 @@ static const char *output_name;
|
||||
static int output_fd;
|
||||
static int print_free_counters_hint;
|
||||
static int print_mixed_hw_group_error;
|
||||
static u64 *walltime_run;
|
||||
|
||||
struct perf_stat {
|
||||
bool record;
|
||||
@ -569,7 +571,7 @@ static struct perf_evsel *perf_evsel__reset_weak_group(struct perf_evsel *evsel)
|
||||
return leader;
|
||||
}
|
||||
|
||||
static int __run_perf_stat(int argc, const char **argv)
|
||||
static int __run_perf_stat(int argc, const char **argv, int run_idx)
|
||||
{
|
||||
int interval = stat_config.interval;
|
||||
int times = stat_config.times;
|
||||
@ -752,6 +754,9 @@ try_again:
|
||||
|
||||
t1 = rdclock();
|
||||
|
||||
if (walltime_run_table)
|
||||
walltime_run[run_idx] = t1 - t0;
|
||||
|
||||
update_stats(&walltime_nsecs_stats, t1 - t0);
|
||||
|
||||
/*
|
||||
@ -766,7 +771,7 @@ try_again:
|
||||
return WEXITSTATUS(status);
|
||||
}
|
||||
|
||||
static int run_perf_stat(int argc, const char **argv)
|
||||
static int run_perf_stat(int argc, const char **argv, int run_idx)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@ -779,7 +784,7 @@ static int run_perf_stat(int argc, const char **argv)
|
||||
if (sync_run)
|
||||
sync();
|
||||
|
||||
ret = __run_perf_stat(argc, argv);
|
||||
ret = __run_perf_stat(argc, argv, run_idx);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -1764,19 +1769,67 @@ static void print_header(int argc, const char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
static int get_precision(double num)
|
||||
{
|
||||
if (num > 1)
|
||||
return 0;
|
||||
|
||||
return lround(ceil(-log10(num)));
|
||||
}
|
||||
|
||||
static void print_table(FILE *output, int precision, double avg)
|
||||
{
|
||||
char tmp[64];
|
||||
int idx, indent = 0;
|
||||
|
||||
scnprintf(tmp, 64, " %17.*f", precision, avg);
|
||||
while (tmp[indent] == ' ')
|
||||
indent++;
|
||||
|
||||
fprintf(output, "%*s# Table of individual measurements:\n", indent, "");
|
||||
|
||||
for (idx = 0; idx < run_count; idx++) {
|
||||
double run = (double) walltime_run[idx] / NSEC_PER_SEC;
|
||||
int h, n = 1 + abs((int) (100.0 * (run - avg)/run) / 5);
|
||||
|
||||
fprintf(output, " %17.*f (%+.*f) ",
|
||||
precision, run, precision, run - avg);
|
||||
|
||||
for (h = 0; h < n; h++)
|
||||
fprintf(output, "#");
|
||||
|
||||
fprintf(output, "\n");
|
||||
}
|
||||
|
||||
fprintf(output, "\n%*s# Final result:\n", indent, "");
|
||||
}
|
||||
|
||||
static void print_footer(void)
|
||||
{
|
||||
double avg = avg_stats(&walltime_nsecs_stats) / NSEC_PER_SEC;
|
||||
FILE *output = stat_config.output;
|
||||
int n;
|
||||
|
||||
if (!null_run)
|
||||
fprintf(output, "\n");
|
||||
fprintf(output, " %17.9f seconds time elapsed",
|
||||
avg_stats(&walltime_nsecs_stats) / NSEC_PER_SEC);
|
||||
if (run_count > 1) {
|
||||
fprintf(output, " ");
|
||||
print_noise_pct(stddev_stats(&walltime_nsecs_stats),
|
||||
avg_stats(&walltime_nsecs_stats));
|
||||
|
||||
if (run_count == 1) {
|
||||
fprintf(output, " %17.9f seconds time elapsed", avg);
|
||||
} else {
|
||||
double sd = stddev_stats(&walltime_nsecs_stats) / NSEC_PER_SEC;
|
||||
/*
|
||||
* Display at most 2 more significant
|
||||
* digits than the stddev inaccuracy.
|
||||
*/
|
||||
int precision = get_precision(sd) + 2;
|
||||
|
||||
if (walltime_run_table)
|
||||
print_table(output, precision, avg);
|
||||
|
||||
fprintf(output, " %17.*f +- %.*f seconds time elapsed",
|
||||
precision, avg, precision, sd);
|
||||
|
||||
print_noise_pct(sd, avg);
|
||||
}
|
||||
fprintf(output, "\n\n");
|
||||
|
||||
@ -1952,6 +2005,8 @@ static const struct option stat_options[] = {
|
||||
"be more verbose (show counter open errors, etc)"),
|
||||
OPT_INTEGER('r', "repeat", &run_count,
|
||||
"repeat command and print average + stddev (max: 100, forever: 0)"),
|
||||
OPT_BOOLEAN(0, "table", &walltime_run_table,
|
||||
"display details about each run (only with -r option)"),
|
||||
OPT_BOOLEAN('n', "null", &null_run,
|
||||
"null run - dont start any counters"),
|
||||
OPT_INCR('d', "detailed", &detailed_run,
|
||||
@ -2843,6 +2898,13 @@ int cmd_stat(int argc, const char **argv)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (walltime_run_table && run_count <= 1) {
|
||||
fprintf(stderr, "--table is only supported with -r\n");
|
||||
parse_options_usage(stat_usage, stat_options, "r", 1);
|
||||
parse_options_usage(NULL, stat_options, "table", 0);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (output_fd < 0) {
|
||||
fprintf(stderr, "argument to --log-fd must be a > 0\n");
|
||||
parse_options_usage(stat_usage, stat_options, "log-fd", 0);
|
||||
@ -2897,6 +2959,14 @@ int cmd_stat(int argc, const char **argv)
|
||||
run_count = 1;
|
||||
}
|
||||
|
||||
if (walltime_run_table) {
|
||||
walltime_run = zalloc(run_count * sizeof(walltime_run[0]));
|
||||
if (!walltime_run) {
|
||||
pr_err("failed to setup -r option");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if ((stat_config.aggr_mode == AGGR_THREAD) &&
|
||||
!target__has_task(&target)) {
|
||||
if (!target.system_wide || target.cpu_list) {
|
||||
@ -3012,7 +3082,7 @@ int cmd_stat(int argc, const char **argv)
|
||||
fprintf(output, "[ perf stat: executing run #%d ... ]\n",
|
||||
run_idx + 1);
|
||||
|
||||
status = run_perf_stat(argc, argv);
|
||||
status = run_perf_stat(argc, argv, run_idx);
|
||||
if (forever && status != -1) {
|
||||
print_counters(NULL, argc, argv);
|
||||
perf_stat__reset_stats();
|
||||
@ -3060,6 +3130,8 @@ int cmd_stat(int argc, const char **argv)
|
||||
perf_stat__exit_aggr_mode();
|
||||
perf_evlist__free_stats(evsel_list);
|
||||
out:
|
||||
free(walltime_run);
|
||||
|
||||
if (smi_cost && smi_reset)
|
||||
sysfs__write_int(FREEZE_ON_SMI_PATH, 0);
|
||||
|
||||
|
@ -533,12 +533,8 @@ static const char *cat_backtrace(union perf_event *event,
|
||||
}
|
||||
|
||||
tal.filtered = 0;
|
||||
thread__find_addr_location(al.thread, cpumode,
|
||||
MAP__FUNCTION, ip, &tal);
|
||||
|
||||
if (tal.sym)
|
||||
fprintf(f, "..... %016" PRIx64 " %s\n", ip,
|
||||
tal.sym->name);
|
||||
if (thread__find_symbol(al.thread, cpumode, ip, &tal))
|
||||
fprintf(f, "..... %016" PRIx64 " %s\n", ip, tal.sym->name);
|
||||
else
|
||||
fprintf(f, "..... %016" PRIx64 "\n", ip);
|
||||
}
|
||||
|
@ -742,7 +742,7 @@ static void perf_event__process_sample(struct perf_tool *tool,
|
||||
"Kernel address maps (/proc/{kallsyms,modules}) are restricted.\n\n"
|
||||
"Check /proc/sys/kernel/kptr_restrict.\n\n"
|
||||
"Kernel%s samples will not be resolved.\n",
|
||||
al.map && !RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION]) ?
|
||||
al.map && map__has_symbols(al.map) ?
|
||||
" modules" : "");
|
||||
if (use_browser <= 0)
|
||||
sleep(5);
|
||||
@ -750,7 +750,7 @@ static void perf_event__process_sample(struct perf_tool *tool,
|
||||
machine->kptr_restrict_warned = true;
|
||||
}
|
||||
|
||||
if (al.sym == NULL) {
|
||||
if (al.sym == NULL && al.map != NULL) {
|
||||
const char *msg = "Kernel samples will not be resolved.\n";
|
||||
/*
|
||||
* As we do lazy loading of symtabs we only will know if the
|
||||
@ -764,8 +764,7 @@ static void perf_event__process_sample(struct perf_tool *tool,
|
||||
* invalid --vmlinux ;-)
|
||||
*/
|
||||
if (!machine->kptr_restrict_warned && !top->vmlinux_warned &&
|
||||
al.map == machine->vmlinux_maps[MAP__FUNCTION] &&
|
||||
RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION])) {
|
||||
__map__is_kernel(al.map) && map__has_symbols(al.map)) {
|
||||
if (symbol_conf.vmlinux_name) {
|
||||
char serr[256];
|
||||
dso__strerror_load(al.map->dso, serr, sizeof(serr));
|
||||
|
@ -2024,8 +2024,7 @@ static int trace__pgfault(struct trace *trace,
|
||||
if (trace->summary_only)
|
||||
goto out;
|
||||
|
||||
thread__find_addr_location(thread, sample->cpumode, MAP__FUNCTION,
|
||||
sample->ip, &al);
|
||||
thread__find_symbol(thread, sample->cpumode, sample->ip, &al);
|
||||
|
||||
trace__fprintf_entry_head(trace, thread, 0, true, sample->time, trace->output);
|
||||
|
||||
@ -2037,12 +2036,10 @@ static int trace__pgfault(struct trace *trace,
|
||||
|
||||
fprintf(trace->output, "] => ");
|
||||
|
||||
thread__find_addr_location(thread, sample->cpumode, MAP__VARIABLE,
|
||||
sample->addr, &al);
|
||||
thread__find_symbol(thread, sample->cpumode, sample->addr, &al);
|
||||
|
||||
if (!al.map) {
|
||||
thread__find_addr_location(thread, sample->cpumode,
|
||||
MAP__FUNCTION, sample->addr, &al);
|
||||
thread__find_symbol(thread, sample->cpumode, sample->addr, &al);
|
||||
|
||||
if (al.map)
|
||||
map_type = 'x';
|
||||
|
@ -55,23 +55,27 @@ include/uapi/asm-generic/ioctls.h
|
||||
include/uapi/asm-generic/mman-common.h
|
||||
'
|
||||
|
||||
check_2 () {
|
||||
file1=$1
|
||||
file2=$2
|
||||
|
||||
shift
|
||||
shift
|
||||
|
||||
cmd="diff $* $file1 $file2 > /dev/null"
|
||||
|
||||
test -f $file2 &&
|
||||
eval $cmd || echo "Warning: Kernel ABI header at 'tools/$file' differs from latest version at '$file'" >&2
|
||||
}
|
||||
|
||||
check () {
|
||||
file=$1
|
||||
|
||||
shift
|
||||
opts=
|
||||
while [ -n "$*" ]; do
|
||||
opts="$opts \"$1\""
|
||||
shift
|
||||
done
|
||||
|
||||
cmd="diff $opts ../$file ../../$file > /dev/null"
|
||||
|
||||
test -f ../../$file &&
|
||||
eval $cmd || echo "Warning: Kernel ABI header at 'tools/$file' differs from latest version at '$file'" >&2
|
||||
check_2 ../$file ../../$file $*
|
||||
}
|
||||
|
||||
|
||||
# Check if we have the kernel headers (tools/perf/../../include), else
|
||||
# we're probably on a detached tarball, so no point in trying to check
|
||||
# differences.
|
||||
@ -83,7 +87,7 @@ for i in $HEADERS; do
|
||||
done
|
||||
|
||||
# diff with extra ignore lines
|
||||
check arch/x86/lib/memcpy_64.S -I "^EXPORT_SYMBOL" -I "^#include <asm/export.h>"
|
||||
check arch/x86/lib/memset_64.S -I "^EXPORT_SYMBOL" -I "^#include <asm/export.h>"
|
||||
check include/uapi/asm-generic/mman.h -I "^#include <\(uapi/\)*asm-generic/mman-common.h>"
|
||||
check include/uapi/linux/mman.h -I "^#include <\(uapi/\)*asm/mman.h>"
|
||||
check arch/x86/lib/memcpy_64.S '-I "^EXPORT_SYMBOL" -I "^#include <asm/export.h>"'
|
||||
check arch/x86/lib/memset_64.S '-I "^EXPORT_SYMBOL" -I "^#include <asm/export.h>"'
|
||||
check include/uapi/asm-generic/mman.h '-I "^#include <\(uapi/\)*asm-generic/mman-common.h>"'
|
||||
check include/uapi/linux/mman.h '-I "^#include <\(uapi/\)*asm/mman.h>"'
|
||||
|
@ -654,6 +654,15 @@ static int perf_test__list(int argc, const char **argv)
|
||||
continue;
|
||||
|
||||
pr_info("%2d: %s\n", i, t->desc);
|
||||
|
||||
if (t->subtest.get_nr) {
|
||||
int subn = t->subtest.get_nr();
|
||||
int subi;
|
||||
|
||||
for (subi = 0; subi < subn; subi++)
|
||||
pr_info("%2d:%1d: %s\n", i, subi + 1,
|
||||
t->subtest.get_desc(subi));
|
||||
}
|
||||
}
|
||||
|
||||
perf_test__list_shell(argc, argv, i);
|
||||
|
@ -236,14 +236,13 @@ static int read_object_code(u64 addr, size_t len, u8 cpumode,
|
||||
|
||||
pr_debug("Reading object code for memory address: %#"PRIx64"\n", addr);
|
||||
|
||||
thread__find_addr_map(thread, cpumode, MAP__FUNCTION, addr, &al);
|
||||
if (!al.map || !al.map->dso) {
|
||||
if (!thread__find_map(thread, cpumode, addr, &al) || !al.map->dso) {
|
||||
if (cpumode == PERF_RECORD_MISC_HYPERVISOR) {
|
||||
pr_debug("Hypervisor address can not be resolved - skipping\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
pr_debug("thread__find_addr_map failed\n");
|
||||
pr_debug("thread__find_map failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -131,20 +131,20 @@ struct machine *setup_fake_machine(struct machines *machines)
|
||||
goto out;
|
||||
|
||||
/* emulate dso__load() */
|
||||
dso__set_loaded(dso, MAP__FUNCTION);
|
||||
dso__set_loaded(dso);
|
||||
|
||||
for (k = 0; k < fake_symbols[i].nr_syms; k++) {
|
||||
struct symbol *sym;
|
||||
struct fake_sym *fsym = &fake_symbols[i].syms[k];
|
||||
|
||||
sym = symbol__new(fsym->start, fsym->length,
|
||||
STB_GLOBAL, fsym->name);
|
||||
STB_GLOBAL, STT_FUNC, fsym->name);
|
||||
if (sym == NULL) {
|
||||
dso__put(dso);
|
||||
goto out;
|
||||
}
|
||||
|
||||
symbols__insert(&dso->symbols[MAP__FUNCTION], sym);
|
||||
symbols__insert(&dso->symbols, sym);
|
||||
}
|
||||
|
||||
dso__put(dso);
|
||||
|
@ -188,9 +188,8 @@ static int mmap_events(synth_cb synth)
|
||||
|
||||
pr_debug("looking for map %p\n", td->map);
|
||||
|
||||
thread__find_addr_map(thread,
|
||||
PERF_RECORD_MISC_USER, MAP__FUNCTION,
|
||||
(unsigned long) (td->map + 1), &al);
|
||||
thread__find_map(thread, PERF_RECORD_MISC_USER,
|
||||
(unsigned long) (td->map + 1), &al);
|
||||
|
||||
thread__put(thread);
|
||||
|
||||
@ -218,7 +217,7 @@ static int mmap_events(synth_cb synth)
|
||||
* perf_event__synthesize_threads (global)
|
||||
*
|
||||
* We test we can find all memory maps via:
|
||||
* thread__find_addr_map
|
||||
* thread__find_map
|
||||
*
|
||||
* by using all thread objects.
|
||||
*/
|
||||
|
@ -19,8 +19,7 @@ int test__vmlinux_matches_kallsyms(struct test *test __maybe_unused, int subtest
|
||||
struct symbol *sym;
|
||||
struct map *kallsyms_map, *vmlinux_map, *map;
|
||||
struct machine kallsyms, vmlinux;
|
||||
enum map_type type = MAP__FUNCTION;
|
||||
struct maps *maps = &vmlinux.kmaps.maps[type];
|
||||
struct maps *maps = machine__kernel_maps(&vmlinux);
|
||||
u64 mem_start, mem_end;
|
||||
bool header_printed;
|
||||
|
||||
@ -56,7 +55,7 @@ int test__vmlinux_matches_kallsyms(struct test *test __maybe_unused, int subtest
|
||||
* be compacted against the list of modules found in the "vmlinux"
|
||||
* code and with the one got from /proc/modules from the "kallsyms" code.
|
||||
*/
|
||||
if (machine__load_kallsyms(&kallsyms, "/proc/kallsyms", type) <= 0) {
|
||||
if (machine__load_kallsyms(&kallsyms, "/proc/kallsyms") <= 0) {
|
||||
pr_debug("dso__load_kallsyms ");
|
||||
goto out;
|
||||
}
|
||||
@ -94,7 +93,7 @@ int test__vmlinux_matches_kallsyms(struct test *test __maybe_unused, int subtest
|
||||
* maps__reloc_vmlinux will notice and set proper ->[un]map_ip routines
|
||||
* to fixup the symbols.
|
||||
*/
|
||||
if (machine__load_vmlinux_path(&vmlinux, type) <= 0) {
|
||||
if (machine__load_vmlinux_path(&vmlinux) <= 0) {
|
||||
pr_debug("Couldn't find a vmlinux that matches the kernel running on this machine, skipping test\n");
|
||||
err = TEST_SKIP;
|
||||
goto out;
|
||||
@ -108,7 +107,7 @@ int test__vmlinux_matches_kallsyms(struct test *test __maybe_unused, int subtest
|
||||
* in the kallsyms dso. For the ones that are in both, check its names and
|
||||
* end addresses too.
|
||||
*/
|
||||
for (nd = rb_first(&vmlinux_map->dso->symbols[type]); nd; nd = rb_next(nd)) {
|
||||
map__for_each_symbol(vmlinux_map, sym, nd) {
|
||||
struct symbol *pair, *first_pair;
|
||||
|
||||
sym = rb_entry(nd, struct symbol, rb_node);
|
||||
@ -119,8 +118,7 @@ int test__vmlinux_matches_kallsyms(struct test *test __maybe_unused, int subtest
|
||||
mem_start = vmlinux_map->unmap_ip(vmlinux_map, sym->start);
|
||||
mem_end = vmlinux_map->unmap_ip(vmlinux_map, sym->end);
|
||||
|
||||
first_pair = machine__find_kernel_symbol(&kallsyms, type,
|
||||
mem_start, NULL);
|
||||
first_pair = machine__find_kernel_symbol(&kallsyms, mem_start, NULL);
|
||||
pair = first_pair;
|
||||
|
||||
if (pair && UM(pair->start) == mem_start) {
|
||||
@ -149,7 +147,7 @@ next_pair:
|
||||
*/
|
||||
continue;
|
||||
} else {
|
||||
pair = machine__find_kernel_symbol_by_name(&kallsyms, type, sym->name, NULL);
|
||||
pair = machine__find_kernel_symbol_by_name(&kallsyms, sym->name, NULL);
|
||||
if (pair) {
|
||||
if (UM(pair->start) == mem_start)
|
||||
goto next_pair;
|
||||
@ -183,7 +181,7 @@ next_pair:
|
||||
* so use the short name, less descriptive but the same ("[kernel]" in
|
||||
* both cases.
|
||||
*/
|
||||
pair = map_groups__find_by_name(&kallsyms.kmaps, type,
|
||||
pair = map_groups__find_by_name(&kallsyms.kmaps,
|
||||
(map->dso->kernel ?
|
||||
map->dso->short_name :
|
||||
map->dso->name));
|
||||
@ -206,7 +204,7 @@ next_pair:
|
||||
mem_start = vmlinux_map->unmap_ip(vmlinux_map, map->start);
|
||||
mem_end = vmlinux_map->unmap_ip(vmlinux_map, map->end);
|
||||
|
||||
pair = map_groups__find(&kallsyms.kmaps, type, mem_start);
|
||||
pair = map_groups__find(&kallsyms.kmaps, mem_start);
|
||||
if (pair == NULL || pair->priv)
|
||||
continue;
|
||||
|
||||
@ -228,7 +226,7 @@ next_pair:
|
||||
|
||||
header_printed = false;
|
||||
|
||||
maps = &kallsyms.kmaps.maps[type];
|
||||
maps = machine__kernel_maps(&kallsyms);
|
||||
|
||||
for (map = maps__first(maps); map; map = map__next(map)) {
|
||||
if (!map->priv) {
|
||||
|
@ -104,7 +104,7 @@ int map__browse(struct map *map)
|
||||
{
|
||||
struct map_browser mb = {
|
||||
.b = {
|
||||
.entries = &map->dso->symbols[map->type],
|
||||
.entries = &map->dso->symbols,
|
||||
.refresh = ui_browser__rb_tree_refresh,
|
||||
.seek = ui_browser__rb_tree_seek,
|
||||
.write = map_browser__write,
|
||||
|
@ -819,8 +819,7 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
|
||||
}
|
||||
|
||||
if (h->ms.map == NULL && verbose > 1) {
|
||||
__map_groups__fprintf_maps(h->thread->mg,
|
||||
MAP__FUNCTION, fp);
|
||||
map_groups__fprintf(h->thread->mg, fp);
|
||||
fprintf(fp, "%.10s end\n", graph_dotted_line);
|
||||
}
|
||||
}
|
||||
|
@ -1679,7 +1679,7 @@ struct sym_args {
|
||||
static bool kern_sym_match(struct sym_args *args, const char *name, char type)
|
||||
{
|
||||
/* A function with the same name, and global or the n'th found or any */
|
||||
return symbol_type__is_a(type, MAP__FUNCTION) &&
|
||||
return kallsyms__is_function(type) &&
|
||||
!strcmp(name, args->name) &&
|
||||
((args->global && isupper(type)) ||
|
||||
(args->selected && ++(args->cnt) == args->idx) ||
|
||||
@ -1784,7 +1784,7 @@ static int find_entire_kern_cb(void *arg, const char *name __maybe_unused,
|
||||
{
|
||||
struct sym_args *args = arg;
|
||||
|
||||
if (!symbol_type__is_a(type, MAP__FUNCTION))
|
||||
if (!kallsyms__is_function(type))
|
||||
return 0;
|
||||
|
||||
if (!args->started) {
|
||||
@ -1915,7 +1915,7 @@ static void print_duplicate_syms(struct dso *dso, const char *sym_name)
|
||||
|
||||
pr_err("Multiple symbols with name '%s'\n", sym_name);
|
||||
|
||||
sym = dso__first_symbol(dso, MAP__FUNCTION);
|
||||
sym = dso__first_symbol(dso);
|
||||
while (sym) {
|
||||
if (dso_sym_match(sym, sym_name, &cnt, -1)) {
|
||||
pr_err("#%d\t0x%"PRIx64"\t%c\t%s\n",
|
||||
@ -1945,7 +1945,7 @@ static int find_dso_sym(struct dso *dso, const char *sym_name, u64 *start,
|
||||
*start = 0;
|
||||
*size = 0;
|
||||
|
||||
sym = dso__first_symbol(dso, MAP__FUNCTION);
|
||||
sym = dso__first_symbol(dso);
|
||||
while (sym) {
|
||||
if (*start) {
|
||||
if (!*size)
|
||||
@ -1972,8 +1972,8 @@ static int find_dso_sym(struct dso *dso, const char *sym_name, u64 *start,
|
||||
|
||||
static int addr_filter__entire_dso(struct addr_filter *filt, struct dso *dso)
|
||||
{
|
||||
struct symbol *first_sym = dso__first_symbol(dso, MAP__FUNCTION);
|
||||
struct symbol *last_sym = dso__last_symbol(dso, MAP__FUNCTION);
|
||||
struct symbol *first_sym = dso__first_symbol(dso);
|
||||
struct symbol *last_sym = dso__last_symbol(dso);
|
||||
|
||||
if (!first_sym || !last_sym) {
|
||||
pr_err("Failed to determine filter for %s\nNo symbols found.\n",
|
||||
|
@ -47,9 +47,7 @@ int build_id__mark_dso_hit(struct perf_tool *tool __maybe_unused,
|
||||
return -1;
|
||||
}
|
||||
|
||||
thread__find_addr_map(thread, sample->cpumode, MAP__FUNCTION, sample->ip, &al);
|
||||
|
||||
if (al.map != NULL)
|
||||
if (thread__find_map(thread, sample->cpumode, sample->ip, &al))
|
||||
al.map->dso->hit = 1;
|
||||
|
||||
thread__put(thread);
|
||||
|
@ -269,9 +269,7 @@ static u32 cs_etm__mem_access(struct cs_etm_queue *etmq, u64 address,
|
||||
thread = etmq->etm->unknown_thread;
|
||||
}
|
||||
|
||||
thread__find_addr_map(thread, cpumode, MAP__FUNCTION, address, &al);
|
||||
|
||||
if (!al.map || !al.map->dso)
|
||||
if (!thread__find_map(thread, cpumode, address, &al) || !al.map->dso)
|
||||
return 0;
|
||||
|
||||
if (al.map->dso->data.status == DSO_DATA_STATUS_ERROR &&
|
||||
|
@ -247,9 +247,9 @@ static int db_ids_from_al(struct db_export *dbe, struct addr_location *al,
|
||||
*dso_db_id = dso->db_id;
|
||||
|
||||
if (!al->sym) {
|
||||
al->sym = symbol__new(al->addr, 0, 0, "unknown");
|
||||
al->sym = symbol__new(al->addr, 0, 0, 0, "unknown");
|
||||
if (al->sym)
|
||||
dso__insert_symbol(dso, al->map->type, al->sym);
|
||||
dso__insert_symbol(dso, al->sym);
|
||||
}
|
||||
|
||||
if (al->sym) {
|
||||
@ -315,8 +315,7 @@ static struct call_path *call_path_from_sample(struct db_export *dbe,
|
||||
al.addr = node->ip;
|
||||
|
||||
if (al.map && !al.sym)
|
||||
al.sym = dso__find_symbol(al.map->dso, MAP__FUNCTION,
|
||||
al.addr);
|
||||
al.sym = dso__find_symbol(al.map->dso, al.addr);
|
||||
|
||||
db_ids_from_al(dbe, &al, &dso_db_id, &sym_db_id, &offset);
|
||||
|
||||
|
@ -1014,7 +1014,7 @@ struct map *dso__new_map(const char *name)
|
||||
struct dso *dso = dso__new(name);
|
||||
|
||||
if (dso)
|
||||
map = map__new2(0, dso, MAP__FUNCTION);
|
||||
map = map__new2(0, dso);
|
||||
|
||||
return map;
|
||||
}
|
||||
@ -1176,19 +1176,19 @@ int dso__name_len(const struct dso *dso)
|
||||
return dso->short_name_len;
|
||||
}
|
||||
|
||||
bool dso__loaded(const struct dso *dso, enum map_type type)
|
||||
bool dso__loaded(const struct dso *dso)
|
||||
{
|
||||
return dso->loaded & (1 << type);
|
||||
return dso->loaded;
|
||||
}
|
||||
|
||||
bool dso__sorted_by_name(const struct dso *dso, enum map_type type)
|
||||
bool dso__sorted_by_name(const struct dso *dso)
|
||||
{
|
||||
return dso->sorted_by_name & (1 << type);
|
||||
return dso->sorted_by_name;
|
||||
}
|
||||
|
||||
void dso__set_sorted_by_name(struct dso *dso, enum map_type type)
|
||||
void dso__set_sorted_by_name(struct dso *dso)
|
||||
{
|
||||
dso->sorted_by_name |= (1 << type);
|
||||
dso->sorted_by_name = true;
|
||||
}
|
||||
|
||||
struct dso *dso__new(const char *name)
|
||||
@ -1196,12 +1196,10 @@ struct dso *dso__new(const char *name)
|
||||
struct dso *dso = calloc(1, sizeof(*dso) + strlen(name) + 1);
|
||||
|
||||
if (dso != NULL) {
|
||||
int i;
|
||||
strcpy(dso->name, name);
|
||||
dso__set_long_name(dso, dso->name, false);
|
||||
dso__set_short_name(dso, dso->name, false);
|
||||
for (i = 0; i < MAP__NR_TYPES; ++i)
|
||||
dso->symbols[i] = dso->symbol_names[i] = RB_ROOT;
|
||||
dso->symbols = dso->symbol_names = RB_ROOT;
|
||||
dso->data.cache = RB_ROOT;
|
||||
dso->inlined_nodes = RB_ROOT;
|
||||
dso->srclines = RB_ROOT;
|
||||
@ -1231,8 +1229,6 @@ struct dso *dso__new(const char *name)
|
||||
|
||||
void dso__delete(struct dso *dso)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!RB_EMPTY_NODE(&dso->rb_node))
|
||||
pr_err("DSO %s is still in rbtree when being deleted!\n",
|
||||
dso->long_name);
|
||||
@ -1240,8 +1236,7 @@ void dso__delete(struct dso *dso)
|
||||
/* free inlines first, as they reference symbols */
|
||||
inlines__tree_delete(&dso->inlined_nodes);
|
||||
srcline__tree_delete(&dso->srclines);
|
||||
for (i = 0; i < MAP__NR_TYPES; ++i)
|
||||
symbols__delete(&dso->symbols[i]);
|
||||
symbols__delete(&dso->symbols);
|
||||
|
||||
if (dso->short_name_allocated) {
|
||||
zfree((char **)&dso->short_name);
|
||||
@ -1451,9 +1446,7 @@ size_t __dsos__fprintf(struct list_head *head, FILE *fp)
|
||||
size_t ret = 0;
|
||||
|
||||
list_for_each_entry(pos, head, node) {
|
||||
int i;
|
||||
for (i = 0; i < MAP__NR_TYPES; ++i)
|
||||
ret += dso__fprintf(pos, i, fp);
|
||||
ret += dso__fprintf(pos, fp);
|
||||
}
|
||||
|
||||
return ret;
|
||||
@ -1467,18 +1460,17 @@ size_t dso__fprintf_buildid(struct dso *dso, FILE *fp)
|
||||
return fprintf(fp, "%s", sbuild_id);
|
||||
}
|
||||
|
||||
size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp)
|
||||
size_t dso__fprintf(struct dso *dso, FILE *fp)
|
||||
{
|
||||
struct rb_node *nd;
|
||||
size_t ret = fprintf(fp, "dso: %s (", dso->short_name);
|
||||
|
||||
if (dso->short_name != dso->long_name)
|
||||
ret += fprintf(fp, "%s, ", dso->long_name);
|
||||
ret += fprintf(fp, "%s, %sloaded, ", map_type__name[type],
|
||||
dso__loaded(dso, type) ? "" : "NOT ");
|
||||
ret += fprintf(fp, "%sloaded, ", dso__loaded(dso) ? "" : "NOT ");
|
||||
ret += dso__fprintf_buildid(dso, fp);
|
||||
ret += fprintf(fp, ")\n");
|
||||
for (nd = rb_first(&dso->symbols[type]); nd; nd = rb_next(nd)) {
|
||||
for (nd = rb_first(&dso->symbols); nd; nd = rb_next(nd)) {
|
||||
struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
|
||||
ret += symbol__fprintf(pos, fp);
|
||||
}
|
||||
|
@ -140,14 +140,14 @@ struct dso {
|
||||
struct list_head node;
|
||||
struct rb_node rb_node; /* rbtree node sorted by long name */
|
||||
struct rb_root *root; /* root of rbtree that rb_node is in */
|
||||
struct rb_root symbols[MAP__NR_TYPES];
|
||||
struct rb_root symbol_names[MAP__NR_TYPES];
|
||||
struct rb_root symbols;
|
||||
struct rb_root symbol_names;
|
||||
struct rb_root inlined_nodes;
|
||||
struct rb_root srclines;
|
||||
struct {
|
||||
u64 addr;
|
||||
struct symbol *symbol;
|
||||
} last_find_result[MAP__NR_TYPES];
|
||||
} last_find_result;
|
||||
void *a2l;
|
||||
char *symsrc_filename;
|
||||
unsigned int a2l_fails;
|
||||
@ -164,8 +164,8 @@ struct dso {
|
||||
u8 short_name_allocated:1;
|
||||
u8 long_name_allocated:1;
|
||||
u8 is_64_bit:1;
|
||||
u8 sorted_by_name;
|
||||
u8 loaded;
|
||||
bool sorted_by_name;
|
||||
bool loaded;
|
||||
u8 rel;
|
||||
u8 build_id[BUILD_ID_SIZE];
|
||||
u64 text_offset;
|
||||
@ -202,14 +202,13 @@ struct dso {
|
||||
* @dso: the 'struct dso *' in which symbols itereated
|
||||
* @pos: the 'struct symbol *' to use as a loop cursor
|
||||
* @n: the 'struct rb_node *' to use as a temporary storage
|
||||
* @type: the 'enum map_type' type of symbols
|
||||
*/
|
||||
#define dso__for_each_symbol(dso, pos, n, type) \
|
||||
symbols__for_each_entry(&(dso)->symbols[(type)], pos, n)
|
||||
#define dso__for_each_symbol(dso, pos, n) \
|
||||
symbols__for_each_entry(&(dso)->symbols, pos, n)
|
||||
|
||||
static inline void dso__set_loaded(struct dso *dso, enum map_type type)
|
||||
static inline void dso__set_loaded(struct dso *dso)
|
||||
{
|
||||
dso->loaded |= (1 << type);
|
||||
dso->loaded = true;
|
||||
}
|
||||
|
||||
struct dso *dso__new(const char *name);
|
||||
@ -231,11 +230,16 @@ static inline void __dso__zput(struct dso **dso)
|
||||
|
||||
#define dso__zput(dso) __dso__zput(&dso)
|
||||
|
||||
bool dso__loaded(const struct dso *dso, enum map_type type);
|
||||
bool dso__loaded(const struct dso *dso);
|
||||
|
||||
bool dso__sorted_by_name(const struct dso *dso, enum map_type type);
|
||||
void dso__set_sorted_by_name(struct dso *dso, enum map_type type);
|
||||
void dso__sort_by_name(struct dso *dso, enum map_type type);
|
||||
static inline bool dso__has_symbols(const struct dso *dso)
|
||||
{
|
||||
return !RB_EMPTY_ROOT(&dso->symbols);
|
||||
}
|
||||
|
||||
bool dso__sorted_by_name(const struct dso *dso);
|
||||
void dso__set_sorted_by_name(struct dso *dso);
|
||||
void dso__sort_by_name(struct dso *dso);
|
||||
|
||||
void dso__set_build_id(struct dso *dso, void *build_id);
|
||||
bool dso__build_id_equal(const struct dso *dso, u8 *build_id);
|
||||
@ -349,9 +353,8 @@ size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp,
|
||||
size_t __dsos__fprintf(struct list_head *head, FILE *fp);
|
||||
|
||||
size_t dso__fprintf_buildid(struct dso *dso, FILE *fp);
|
||||
size_t dso__fprintf_symbols_by_name(struct dso *dso,
|
||||
enum map_type type, FILE *fp);
|
||||
size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp);
|
||||
size_t dso__fprintf_symbols_by_name(struct dso *dso, FILE *fp);
|
||||
size_t dso__fprintf(struct dso *dso, FILE *fp);
|
||||
|
||||
static inline bool dso__is_vmlinux(struct dso *dso)
|
||||
{
|
||||
|
@ -464,8 +464,7 @@ int perf_event__synthesize_modules(struct perf_tool *tool,
|
||||
{
|
||||
int rc = 0;
|
||||
struct map *pos;
|
||||
struct map_groups *kmaps = &machine->kmaps;
|
||||
struct maps *maps = &kmaps->maps[MAP__FUNCTION];
|
||||
struct maps *maps = machine__kernel_maps(machine);
|
||||
union perf_event *event = zalloc((sizeof(event->mmap) +
|
||||
machine->id_hdr_size));
|
||||
if (event == NULL) {
|
||||
@ -869,7 +868,7 @@ static int find_symbol_cb(void *arg, const char *name, char type,
|
||||
* Must be a function or at least an alias, as in PARISC64, where "_text" is
|
||||
* an 'A' to the same address as "_stext".
|
||||
*/
|
||||
if (!(symbol_type__is_a(type, MAP__FUNCTION) ||
|
||||
if (!(kallsyms__is_function(type) ||
|
||||
type == 'A') || strcmp(name, args->name))
|
||||
return 0;
|
||||
|
||||
@ -1489,9 +1488,8 @@ int perf_event__process(struct perf_tool *tool __maybe_unused,
|
||||
return machine__process_event(machine, event, sample);
|
||||
}
|
||||
|
||||
void thread__find_addr_map(struct thread *thread, u8 cpumode,
|
||||
enum map_type type, u64 addr,
|
||||
struct addr_location *al)
|
||||
struct map *thread__find_map(struct thread *thread, u8 cpumode, u64 addr,
|
||||
struct addr_location *al)
|
||||
{
|
||||
struct map_groups *mg = thread->mg;
|
||||
struct machine *machine = mg->machine;
|
||||
@ -1505,7 +1503,7 @@ void thread__find_addr_map(struct thread *thread, u8 cpumode,
|
||||
|
||||
if (machine == NULL) {
|
||||
al->map = NULL;
|
||||
return;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (cpumode == PERF_RECORD_MISC_KERNEL && perf_host) {
|
||||
@ -1533,10 +1531,10 @@ void thread__find_addr_map(struct thread *thread, u8 cpumode,
|
||||
!perf_host)
|
||||
al->filtered |= (1 << HIST_FILTER__HOST);
|
||||
|
||||
return;
|
||||
return NULL;
|
||||
}
|
||||
try_again:
|
||||
al->map = map_groups__find(mg, type, al->addr);
|
||||
al->map = map_groups__find(mg, al->addr);
|
||||
if (al->map == NULL) {
|
||||
/*
|
||||
* If this is outside of all known maps, and is a negative
|
||||
@ -1563,17 +1561,17 @@ try_again:
|
||||
map__load(al->map);
|
||||
al->addr = al->map->map_ip(al->map, al->addr);
|
||||
}
|
||||
|
||||
return al->map;
|
||||
}
|
||||
|
||||
void thread__find_addr_location(struct thread *thread,
|
||||
u8 cpumode, enum map_type type, u64 addr,
|
||||
struct addr_location *al)
|
||||
struct symbol *thread__find_symbol(struct thread *thread, u8 cpumode,
|
||||
u64 addr, struct addr_location *al)
|
||||
{
|
||||
thread__find_addr_map(thread, cpumode, type, addr, al);
|
||||
if (al->map != NULL)
|
||||
al->sym = NULL;
|
||||
if (thread__find_map(thread, cpumode, addr, al))
|
||||
al->sym = map__find_symbol(al->map, al->addr);
|
||||
else
|
||||
al->sym = NULL;
|
||||
return al->sym;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1590,7 +1588,7 @@ int machine__resolve(struct machine *machine, struct addr_location *al,
|
||||
return -1;
|
||||
|
||||
dump_printf(" ... thread: %s:%d\n", thread__comm_str(thread), thread->tid);
|
||||
thread__find_addr_map(thread, sample->cpumode, MAP__FUNCTION, sample->ip, al);
|
||||
thread__find_map(thread, sample->cpumode, sample->ip, al);
|
||||
dump_printf(" ...... dso: %s\n",
|
||||
al->map ? al->map->dso->long_name :
|
||||
al->level == 'H' ? "[hypervisor]" : "<not found>");
|
||||
@ -1669,10 +1667,7 @@ bool sample_addr_correlates_sym(struct perf_event_attr *attr)
|
||||
void thread__resolve(struct thread *thread, struct addr_location *al,
|
||||
struct perf_sample *sample)
|
||||
{
|
||||
thread__find_addr_map(thread, sample->cpumode, MAP__FUNCTION, sample->addr, al);
|
||||
if (!al->map)
|
||||
thread__find_addr_map(thread, sample->cpumode, MAP__VARIABLE,
|
||||
sample->addr, al);
|
||||
thread__find_map(thread, sample->cpumode, sample->addr, al);
|
||||
|
||||
al->cpu = sample->cpu;
|
||||
al->sym = NULL;
|
||||
|
@ -114,7 +114,7 @@ gen_build_id(struct buildid_note *note,
|
||||
|
||||
fd = open("/dev/urandom", O_RDONLY);
|
||||
if (fd == -1)
|
||||
err(1, "cannot access /dev/urandom for builid");
|
||||
err(1, "cannot access /dev/urandom for buildid");
|
||||
|
||||
sret = read(fd, note->build_id, sz);
|
||||
|
||||
|
@ -335,8 +335,7 @@ static int intel_bts_get_next_insn(struct intel_bts_queue *btsq, u64 ip)
|
||||
if (!thread)
|
||||
return -1;
|
||||
|
||||
thread__find_addr_map(thread, cpumode, MAP__FUNCTION, ip, &al);
|
||||
if (!al.map || !al.map->dso)
|
||||
if (!thread__find_map(thread, cpumode, ip, &al) || !al.map->dso)
|
||||
goto out_put;
|
||||
|
||||
len = dso__data_read_addr(al.map->dso, al.map, machine, ip, buf,
|
||||
|
@ -442,8 +442,7 @@ static int intel_pt_walk_next_insn(struct intel_pt_insn *intel_pt_insn,
|
||||
}
|
||||
|
||||
while (1) {
|
||||
thread__find_addr_map(thread, cpumode, MAP__FUNCTION, *ip, &al);
|
||||
if (!al.map || !al.map->dso)
|
||||
if (!thread__find_map(thread, cpumode, *ip, &al) || !al.map->dso)
|
||||
return -EINVAL;
|
||||
|
||||
if (al.map->dso->data.status == DSO_DATA_STATUS_ERROR &&
|
||||
@ -596,8 +595,7 @@ static int __intel_pt_pgd_ip(uint64_t ip, void *data)
|
||||
if (!thread)
|
||||
return -EINVAL;
|
||||
|
||||
thread__find_addr_map(thread, cpumode, MAP__FUNCTION, ip, &al);
|
||||
if (!al.map || !al.map->dso)
|
||||
if (!thread__find_map(thread, cpumode, ip, &al) || !al.map->dso)
|
||||
return -EINVAL;
|
||||
|
||||
offset = al.map->map_ip(al.map, ip);
|
||||
@ -1565,7 +1563,7 @@ static u64 intel_pt_switch_ip(struct intel_pt *pt, u64 *ptss_ip)
|
||||
if (map__load(map))
|
||||
return 0;
|
||||
|
||||
start = dso__first_symbol(map->dso, MAP__FUNCTION);
|
||||
start = dso__first_symbol(map->dso);
|
||||
|
||||
for (sym = start; sym; sym = dso__next_symbol(sym)) {
|
||||
if (sym->binding == STB_GLOBAL &&
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
#include "sane_ctype.h"
|
||||
#include <symbol/kallsyms.h>
|
||||
#include <linux/mman.h>
|
||||
|
||||
static void __machine__remove_thread(struct machine *machine, struct thread *th, bool lock);
|
||||
|
||||
@ -81,8 +82,7 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
|
||||
machine->kptr_restrict_warned = false;
|
||||
machine->comm_exec = false;
|
||||
machine->kernel_start = 0;
|
||||
|
||||
memset(machine->vmlinux_maps, 0, sizeof(machine->vmlinux_maps));
|
||||
machine->vmlinux_map = NULL;
|
||||
|
||||
machine->root_dir = strdup(root_dir);
|
||||
if (machine->root_dir == NULL)
|
||||
@ -137,13 +137,11 @@ struct machine *machine__new_kallsyms(void)
|
||||
struct machine *machine = machine__new_host();
|
||||
/*
|
||||
* FIXME:
|
||||
* 1) MAP__FUNCTION will go away when we stop loading separate maps for
|
||||
* functions and data objects.
|
||||
* 2) We should switch to machine__load_kallsyms(), i.e. not explicitely
|
||||
* 1) We should switch to machine__load_kallsyms(), i.e. not explicitely
|
||||
* ask for not using the kcore parsing code, once this one is fixed
|
||||
* to create a map per module.
|
||||
*/
|
||||
if (machine && machine__load_kallsyms(machine, "/proc/kallsyms", MAP__FUNCTION) <= 0) {
|
||||
if (machine && machine__load_kallsyms(machine, "/proc/kallsyms") <= 0) {
|
||||
machine__delete(machine);
|
||||
machine = NULL;
|
||||
}
|
||||
@ -673,8 +671,7 @@ struct map *machine__findnew_module_map(struct machine *machine, u64 start,
|
||||
if (kmod_path__parse_name(&m, filename))
|
||||
return NULL;
|
||||
|
||||
map = map_groups__find_by_name(&machine->kmaps, MAP__FUNCTION,
|
||||
m.name);
|
||||
map = map_groups__find_by_name(&machine->kmaps, m.name);
|
||||
if (map) {
|
||||
/*
|
||||
* If the map's dso is an offline module, give dso__load()
|
||||
@ -689,7 +686,7 @@ struct map *machine__findnew_module_map(struct machine *machine, u64 start,
|
||||
if (dso == NULL)
|
||||
goto out;
|
||||
|
||||
map = map__new2(start, dso, MAP__FUNCTION);
|
||||
map = map__new2(start, dso);
|
||||
if (map == NULL)
|
||||
goto out;
|
||||
|
||||
@ -857,62 +854,44 @@ static int machine__get_running_kernel_start(struct machine *machine,
|
||||
static int
|
||||
__machine__create_kernel_maps(struct machine *machine, struct dso *kernel)
|
||||
{
|
||||
int type;
|
||||
struct kmap *kmap;
|
||||
struct map *map;
|
||||
|
||||
/* In case of renewal the kernel map, destroy previous one */
|
||||
machine__destroy_kernel_maps(machine);
|
||||
|
||||
for (type = 0; type < MAP__NR_TYPES; ++type) {
|
||||
struct kmap *kmap;
|
||||
struct map *map;
|
||||
machine->vmlinux_map = map__new2(0, kernel);
|
||||
if (machine->vmlinux_map == NULL)
|
||||
return -1;
|
||||
|
||||
machine->vmlinux_maps[type] = map__new2(0, kernel, type);
|
||||
if (machine->vmlinux_maps[type] == NULL)
|
||||
return -1;
|
||||
machine->vmlinux_map->map_ip = machine->vmlinux_map->unmap_ip = identity__map_ip;
|
||||
map = machine__kernel_map(machine);
|
||||
kmap = map__kmap(map);
|
||||
if (!kmap)
|
||||
return -1;
|
||||
|
||||
machine->vmlinux_maps[type]->map_ip =
|
||||
machine->vmlinux_maps[type]->unmap_ip =
|
||||
identity__map_ip;
|
||||
map = __machine__kernel_map(machine, type);
|
||||
kmap = map__kmap(map);
|
||||
if (!kmap)
|
||||
return -1;
|
||||
|
||||
kmap->kmaps = &machine->kmaps;
|
||||
map_groups__insert(&machine->kmaps, map);
|
||||
}
|
||||
kmap->kmaps = &machine->kmaps;
|
||||
map_groups__insert(&machine->kmaps, map);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void machine__destroy_kernel_maps(struct machine *machine)
|
||||
{
|
||||
int type;
|
||||
struct kmap *kmap;
|
||||
struct map *map = machine__kernel_map(machine);
|
||||
|
||||
for (type = 0; type < MAP__NR_TYPES; ++type) {
|
||||
struct kmap *kmap;
|
||||
struct map *map = __machine__kernel_map(machine, type);
|
||||
if (map == NULL)
|
||||
return;
|
||||
|
||||
if (map == NULL)
|
||||
continue;
|
||||
|
||||
kmap = map__kmap(map);
|
||||
map_groups__remove(&machine->kmaps, map);
|
||||
if (kmap && kmap->ref_reloc_sym) {
|
||||
/*
|
||||
* ref_reloc_sym is shared among all maps, so free just
|
||||
* on one of them.
|
||||
*/
|
||||
if (type == MAP__FUNCTION) {
|
||||
zfree((char **)&kmap->ref_reloc_sym->name);
|
||||
zfree(&kmap->ref_reloc_sym);
|
||||
} else
|
||||
kmap->ref_reloc_sym = NULL;
|
||||
}
|
||||
|
||||
map__put(machine->vmlinux_maps[type]);
|
||||
machine->vmlinux_maps[type] = NULL;
|
||||
kmap = map__kmap(map);
|
||||
map_groups__remove(&machine->kmaps, map);
|
||||
if (kmap && kmap->ref_reloc_sym) {
|
||||
zfree((char **)&kmap->ref_reloc_sym->name);
|
||||
zfree(&kmap->ref_reloc_sym);
|
||||
}
|
||||
|
||||
map__zput(machine->vmlinux_map);
|
||||
}
|
||||
|
||||
int machines__create_guest_kernel_maps(struct machines *machines)
|
||||
@ -989,32 +968,31 @@ int machines__create_kernel_maps(struct machines *machines, pid_t pid)
|
||||
return machine__create_kernel_maps(machine);
|
||||
}
|
||||
|
||||
int machine__load_kallsyms(struct machine *machine, const char *filename,
|
||||
enum map_type type)
|
||||
int machine__load_kallsyms(struct machine *machine, const char *filename)
|
||||
{
|
||||
struct map *map = machine__kernel_map(machine);
|
||||
int ret = __dso__load_kallsyms(map->dso, filename, map, true);
|
||||
|
||||
if (ret > 0) {
|
||||
dso__set_loaded(map->dso, type);
|
||||
dso__set_loaded(map->dso);
|
||||
/*
|
||||
* Since /proc/kallsyms will have multiple sessions for the
|
||||
* kernel, with modules between them, fixup the end of all
|
||||
* sections.
|
||||
*/
|
||||
__map_groups__fixup_end(&machine->kmaps, type);
|
||||
map_groups__fixup_end(&machine->kmaps);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int machine__load_vmlinux_path(struct machine *machine, enum map_type type)
|
||||
int machine__load_vmlinux_path(struct machine *machine)
|
||||
{
|
||||
struct map *map = machine__kernel_map(machine);
|
||||
int ret = dso__load_vmlinux_path(map->dso, map);
|
||||
|
||||
if (ret > 0)
|
||||
dso__set_loaded(map->dso, type);
|
||||
dso__set_loaded(map->dso);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -1055,10 +1033,9 @@ static bool is_kmod_dso(struct dso *dso)
|
||||
static int map_groups__set_module_path(struct map_groups *mg, const char *path,
|
||||
struct kmod_path *m)
|
||||
{
|
||||
struct map *map;
|
||||
char *long_name;
|
||||
struct map *map = map_groups__find_by_name(mg, m->name);
|
||||
|
||||
map = map_groups__find_by_name(mg, MAP__FUNCTION, m->name);
|
||||
if (map == NULL)
|
||||
return 0;
|
||||
|
||||
@ -1207,19 +1184,14 @@ static int machine__create_modules(struct machine *machine)
|
||||
static void machine__set_kernel_mmap(struct machine *machine,
|
||||
u64 start, u64 end)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAP__NR_TYPES; i++) {
|
||||
machine->vmlinux_maps[i]->start = start;
|
||||
machine->vmlinux_maps[i]->end = end;
|
||||
|
||||
/*
|
||||
* Be a bit paranoid here, some perf.data file came with
|
||||
* a zero sized synthesized MMAP event for the kernel.
|
||||
*/
|
||||
if (start == 0 && end == 0)
|
||||
machine->vmlinux_maps[i]->end = ~0ULL;
|
||||
}
|
||||
machine->vmlinux_map->start = start;
|
||||
machine->vmlinux_map->end = end;
|
||||
/*
|
||||
* Be a bit paranoid here, some perf.data file came with
|
||||
* a zero sized synthesized MMAP event for the kernel.
|
||||
*/
|
||||
if (start == 0 && end == 0)
|
||||
machine->vmlinux_map->end = ~0ULL;
|
||||
}
|
||||
|
||||
int machine__create_kernel_maps(struct machine *machine)
|
||||
@ -1249,7 +1221,7 @@ int machine__create_kernel_maps(struct machine *machine)
|
||||
|
||||
if (!machine__get_running_kernel_start(machine, &name, &addr)) {
|
||||
if (name &&
|
||||
maps__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps, name, addr)) {
|
||||
map__set_kallsyms_ref_reloc_sym(machine->vmlinux_map, name, addr)) {
|
||||
machine__destroy_kernel_maps(machine);
|
||||
return -1;
|
||||
}
|
||||
@ -1379,9 +1351,9 @@ static int machine__process_kernel_mmap_event(struct machine *machine,
|
||||
* time /proc/sys/kernel/kptr_restrict was non zero.
|
||||
*/
|
||||
if (event->mmap.pgoff != 0) {
|
||||
maps__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps,
|
||||
symbol_name,
|
||||
event->mmap.pgoff);
|
||||
map__set_kallsyms_ref_reloc_sym(machine->vmlinux_map,
|
||||
symbol_name,
|
||||
event->mmap.pgoff);
|
||||
}
|
||||
|
||||
if (machine__is_default_guest(machine)) {
|
||||
@ -1402,7 +1374,6 @@ int machine__process_mmap2_event(struct machine *machine,
|
||||
{
|
||||
struct thread *thread;
|
||||
struct map *map;
|
||||
enum map_type type;
|
||||
int ret = 0;
|
||||
|
||||
if (dump_trace)
|
||||
@ -1421,11 +1392,6 @@ int machine__process_mmap2_event(struct machine *machine,
|
||||
if (thread == NULL)
|
||||
goto out_problem;
|
||||
|
||||
if (event->header.misc & PERF_RECORD_MISC_MMAP_DATA)
|
||||
type = MAP__VARIABLE;
|
||||
else
|
||||
type = MAP__FUNCTION;
|
||||
|
||||
map = map__new(machine, event->mmap2.start,
|
||||
event->mmap2.len, event->mmap2.pgoff,
|
||||
event->mmap2.maj,
|
||||
@ -1433,7 +1399,7 @@ int machine__process_mmap2_event(struct machine *machine,
|
||||
event->mmap2.ino_generation,
|
||||
event->mmap2.prot,
|
||||
event->mmap2.flags,
|
||||
event->mmap2.filename, type, thread);
|
||||
event->mmap2.filename, thread);
|
||||
|
||||
if (map == NULL)
|
||||
goto out_problem_map;
|
||||
@ -1460,7 +1426,7 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *event
|
||||
{
|
||||
struct thread *thread;
|
||||
struct map *map;
|
||||
enum map_type type;
|
||||
u32 prot = 0;
|
||||
int ret = 0;
|
||||
|
||||
if (dump_trace)
|
||||
@ -1479,16 +1445,14 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *event
|
||||
if (thread == NULL)
|
||||
goto out_problem;
|
||||
|
||||
if (event->header.misc & PERF_RECORD_MISC_MMAP_DATA)
|
||||
type = MAP__VARIABLE;
|
||||
else
|
||||
type = MAP__FUNCTION;
|
||||
if (!(event->header.misc & PERF_RECORD_MISC_MMAP_DATA))
|
||||
prot = PROT_EXEC;
|
||||
|
||||
map = map__new(machine, event->mmap.start,
|
||||
event->mmap.len, event->mmap.pgoff,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, prot, 0,
|
||||
event->mmap.filename,
|
||||
type, thread);
|
||||
thread);
|
||||
|
||||
if (map == NULL)
|
||||
goto out_problem_map;
|
||||
@ -1664,7 +1628,7 @@ static void ip__resolve_ams(struct thread *thread,
|
||||
* Thus, we have to try consecutively until we find a match
|
||||
* or else, the symbol is unknown
|
||||
*/
|
||||
thread__find_cpumode_addr_location(thread, MAP__FUNCTION, ip, &al);
|
||||
thread__find_cpumode_addr_location(thread, ip, &al);
|
||||
|
||||
ams->addr = ip;
|
||||
ams->al_addr = al.addr;
|
||||
@ -1681,15 +1645,7 @@ static void ip__resolve_data(struct thread *thread,
|
||||
|
||||
memset(&al, 0, sizeof(al));
|
||||
|
||||
thread__find_addr_location(thread, m, MAP__VARIABLE, addr, &al);
|
||||
if (al.map == NULL) {
|
||||
/*
|
||||
* some shared data regions have execute bit set which puts
|
||||
* their mapping in the MAP__FUNCTION type array.
|
||||
* Check there as a fallback option before dropping the sample.
|
||||
*/
|
||||
thread__find_addr_location(thread, m, MAP__FUNCTION, addr, &al);
|
||||
}
|
||||
thread__find_symbol(thread, m, addr, &al);
|
||||
|
||||
ams->addr = addr;
|
||||
ams->al_addr = al.addr;
|
||||
@ -1758,8 +1714,7 @@ static int add_callchain_ip(struct thread *thread,
|
||||
al.filtered = 0;
|
||||
al.sym = NULL;
|
||||
if (!cpumode) {
|
||||
thread__find_cpumode_addr_location(thread, MAP__FUNCTION,
|
||||
ip, &al);
|
||||
thread__find_cpumode_addr_location(thread, ip, &al);
|
||||
} else {
|
||||
if (ip >= PERF_CONTEXT_MAX) {
|
||||
switch (ip) {
|
||||
@ -1784,8 +1739,7 @@ static int add_callchain_ip(struct thread *thread,
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
thread__find_addr_location(thread, *cpumode, MAP__FUNCTION,
|
||||
ip, &al);
|
||||
thread__find_symbol(thread, *cpumode, ip, &al);
|
||||
}
|
||||
|
||||
if (al.sym != NULL) {
|
||||
@ -2373,7 +2327,7 @@ char *machine__resolve_kernel_addr(void *vmachine, unsigned long long *addrp, ch
|
||||
{
|
||||
struct machine *machine = vmachine;
|
||||
struct map *map;
|
||||
struct symbol *sym = map_groups__find_symbol(&machine->kmaps, MAP__FUNCTION, *addrp, &map);
|
||||
struct symbol *sym = machine__find_kernel_symbol(machine, *addrp, &map);
|
||||
|
||||
if (sym == NULL)
|
||||
return NULL;
|
||||
|
@ -49,7 +49,7 @@ struct machine {
|
||||
struct perf_env *env;
|
||||
struct dsos dsos;
|
||||
struct map_groups kmaps;
|
||||
struct map *vmlinux_maps[MAP__NR_TYPES];
|
||||
struct map *vmlinux_map;
|
||||
u64 kernel_start;
|
||||
pid_t *current_tid;
|
||||
union { /* Tool specific area */
|
||||
@ -64,16 +64,22 @@ static inline struct threads *machine__threads(struct machine *machine, pid_t ti
|
||||
return &machine->threads[(unsigned int)tid % THREADS__TABLE_SIZE];
|
||||
}
|
||||
|
||||
static inline
|
||||
struct map *__machine__kernel_map(struct machine *machine, enum map_type type)
|
||||
{
|
||||
return machine->vmlinux_maps[type];
|
||||
}
|
||||
|
||||
/*
|
||||
* The main kernel (vmlinux) map
|
||||
*/
|
||||
static inline
|
||||
struct map *machine__kernel_map(struct machine *machine)
|
||||
{
|
||||
return __machine__kernel_map(machine, MAP__FUNCTION);
|
||||
return machine->vmlinux_map;
|
||||
}
|
||||
|
||||
/*
|
||||
* kernel (the one returned by machine__kernel_map()) plus kernel modules maps
|
||||
*/
|
||||
static inline
|
||||
struct maps *machine__kernel_maps(struct machine *machine)
|
||||
{
|
||||
return &machine->kmaps.maps;
|
||||
}
|
||||
|
||||
int machine__get_kernel_start(struct machine *machine);
|
||||
@ -190,44 +196,27 @@ struct dso *machine__findnew_dso(struct machine *machine, const char *filename);
|
||||
size_t machine__fprintf(struct machine *machine, FILE *fp);
|
||||
|
||||
static inline
|
||||
struct symbol *machine__find_kernel_symbol(struct machine *machine,
|
||||
enum map_type type, u64 addr,
|
||||
struct symbol *machine__find_kernel_symbol(struct machine *machine, u64 addr,
|
||||
struct map **mapp)
|
||||
{
|
||||
return map_groups__find_symbol(&machine->kmaps, type, addr, mapp);
|
||||
return map_groups__find_symbol(&machine->kmaps, addr, mapp);
|
||||
}
|
||||
|
||||
static inline
|
||||
struct symbol *machine__find_kernel_symbol_by_name(struct machine *machine,
|
||||
enum map_type type, const char *name,
|
||||
const char *name,
|
||||
struct map **mapp)
|
||||
{
|
||||
return map_groups__find_symbol_by_name(&machine->kmaps, type, name, mapp);
|
||||
}
|
||||
|
||||
static inline
|
||||
struct symbol *machine__find_kernel_function(struct machine *machine, u64 addr,
|
||||
struct map **mapp)
|
||||
{
|
||||
return machine__find_kernel_symbol(machine, MAP__FUNCTION, addr,
|
||||
mapp);
|
||||
}
|
||||
|
||||
static inline
|
||||
struct symbol *machine__find_kernel_function_by_name(struct machine *machine,
|
||||
const char *name,
|
||||
struct map **mapp)
|
||||
{
|
||||
return map_groups__find_function_by_name(&machine->kmaps, name, mapp);
|
||||
return map_groups__find_symbol_by_name(&machine->kmaps, name, mapp);
|
||||
}
|
||||
|
||||
struct map *machine__findnew_module_map(struct machine *machine, u64 start,
|
||||
const char *filename);
|
||||
int arch__fix_module_text_start(u64 *start, const char *name);
|
||||
|
||||
int machine__load_kallsyms(struct machine *machine, const char *filename,
|
||||
enum map_type type);
|
||||
int machine__load_vmlinux_path(struct machine *machine, enum map_type type);
|
||||
int machine__load_kallsyms(struct machine *machine, const char *filename);
|
||||
|
||||
int machine__load_vmlinux_path(struct machine *machine);
|
||||
|
||||
size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp,
|
||||
bool (skip)(struct dso *dso, int parm), int parm);
|
||||
|
@ -22,11 +22,6 @@
|
||||
|
||||
static void __maps__insert(struct maps *maps, struct map *map);
|
||||
|
||||
const char *map_type__name[MAP__NR_TYPES] = {
|
||||
[MAP__FUNCTION] = "Functions",
|
||||
[MAP__VARIABLE] = "Variables",
|
||||
};
|
||||
|
||||
static inline int is_anon_memory(const char *filename, u32 flags)
|
||||
{
|
||||
return flags & MAP_HUGETLB ||
|
||||
@ -129,10 +124,8 @@ static inline bool replace_android_lib(const char *filename, char *newfilename)
|
||||
return false;
|
||||
}
|
||||
|
||||
void map__init(struct map *map, enum map_type type,
|
||||
u64 start, u64 end, u64 pgoff, struct dso *dso)
|
||||
void map__init(struct map *map, u64 start, u64 end, u64 pgoff, struct dso *dso)
|
||||
{
|
||||
map->type = type;
|
||||
map->start = start;
|
||||
map->end = end;
|
||||
map->pgoff = pgoff;
|
||||
@ -149,7 +142,7 @@ void map__init(struct map *map, enum map_type type,
|
||||
struct map *map__new(struct machine *machine, u64 start, u64 len,
|
||||
u64 pgoff, u32 d_maj, u32 d_min, u64 ino,
|
||||
u64 ino_gen, u32 prot, u32 flags, char *filename,
|
||||
enum map_type type, struct thread *thread)
|
||||
struct thread *thread)
|
||||
{
|
||||
struct map *map = malloc(sizeof(*map));
|
||||
struct nsinfo *nsi = NULL;
|
||||
@ -173,7 +166,7 @@ struct map *map__new(struct machine *machine, u64 start, u64 len,
|
||||
map->flags = flags;
|
||||
nsi = nsinfo__get(thread->nsinfo);
|
||||
|
||||
if ((anon || no_dso) && nsi && type == MAP__FUNCTION) {
|
||||
if ((anon || no_dso) && nsi && (prot & PROT_EXEC)) {
|
||||
snprintf(newfilename, sizeof(newfilename),
|
||||
"/tmp/perf-%d.map", nsi->pid);
|
||||
filename = newfilename;
|
||||
@ -203,7 +196,7 @@ struct map *map__new(struct machine *machine, u64 start, u64 len,
|
||||
if (dso == NULL)
|
||||
goto out_delete;
|
||||
|
||||
map__init(map, type, start, start + len, pgoff, dso);
|
||||
map__init(map, start, start + len, pgoff, dso);
|
||||
|
||||
if (anon || no_dso) {
|
||||
map->map_ip = map->unmap_ip = identity__map_ip;
|
||||
@ -213,8 +206,8 @@ struct map *map__new(struct machine *machine, u64 start, u64 len,
|
||||
* functions still return NULL, and we avoid the
|
||||
* unnecessary map__load warning.
|
||||
*/
|
||||
if (type != MAP__FUNCTION)
|
||||
dso__set_loaded(dso, map->type);
|
||||
if (!(prot & PROT_EXEC))
|
||||
dso__set_loaded(dso);
|
||||
}
|
||||
dso->nsinfo = nsi;
|
||||
dso__put(dso);
|
||||
@ -231,7 +224,7 @@ out_delete:
|
||||
* they are loaded) and for vmlinux, where only after we load all the
|
||||
* symbols we'll know where it starts and ends.
|
||||
*/
|
||||
struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
|
||||
struct map *map__new2(u64 start, struct dso *dso)
|
||||
{
|
||||
struct map *map = calloc(1, (sizeof(*map) +
|
||||
(dso->kernel ? sizeof(struct kmap) : 0)));
|
||||
@ -239,7 +232,7 @@ struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
|
||||
/*
|
||||
* ->end will be filled after we load all the symbols
|
||||
*/
|
||||
map__init(map, type, start, 0, 0, dso);
|
||||
map__init(map, start, 0, 0, dso);
|
||||
}
|
||||
|
||||
return map;
|
||||
@ -256,7 +249,12 @@ struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
|
||||
*/
|
||||
bool __map__is_kernel(const struct map *map)
|
||||
{
|
||||
return __machine__kernel_map(map->groups->machine, map->type) == map;
|
||||
return machine__kernel_map(map->groups->machine) == map;
|
||||
}
|
||||
|
||||
bool map__has_symbols(const struct map *map)
|
||||
{
|
||||
return dso__has_symbols(map->dso);
|
||||
}
|
||||
|
||||
static void map__exit(struct map *map)
|
||||
@ -279,7 +277,7 @@ void map__put(struct map *map)
|
||||
|
||||
void map__fixup_start(struct map *map)
|
||||
{
|
||||
struct rb_root *symbols = &map->dso->symbols[map->type];
|
||||
struct rb_root *symbols = &map->dso->symbols;
|
||||
struct rb_node *nd = rb_first(symbols);
|
||||
if (nd != NULL) {
|
||||
struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
|
||||
@ -289,7 +287,7 @@ void map__fixup_start(struct map *map)
|
||||
|
||||
void map__fixup_end(struct map *map)
|
||||
{
|
||||
struct rb_root *symbols = &map->dso->symbols[map->type];
|
||||
struct rb_root *symbols = &map->dso->symbols;
|
||||
struct rb_node *nd = rb_last(symbols);
|
||||
if (nd != NULL) {
|
||||
struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
|
||||
@ -304,7 +302,7 @@ int map__load(struct map *map)
|
||||
const char *name = map->dso->long_name;
|
||||
int nr;
|
||||
|
||||
if (dso__loaded(map->dso, map->type))
|
||||
if (dso__loaded(map->dso))
|
||||
return 0;
|
||||
|
||||
nr = dso__load(map->dso, map);
|
||||
@ -348,7 +346,7 @@ struct symbol *map__find_symbol(struct map *map, u64 addr)
|
||||
if (map__load(map) < 0)
|
||||
return NULL;
|
||||
|
||||
return dso__find_symbol(map->dso, map->type, addr);
|
||||
return dso__find_symbol(map->dso, addr);
|
||||
}
|
||||
|
||||
struct symbol *map__find_symbol_by_name(struct map *map, const char *name)
|
||||
@ -356,10 +354,10 @@ struct symbol *map__find_symbol_by_name(struct map *map, const char *name)
|
||||
if (map__load(map) < 0)
|
||||
return NULL;
|
||||
|
||||
if (!dso__sorted_by_name(map->dso, map->type))
|
||||
dso__sort_by_name(map->dso, map->type);
|
||||
if (!dso__sorted_by_name(map->dso))
|
||||
dso__sort_by_name(map->dso);
|
||||
|
||||
return dso__find_symbol_by_name(map->dso, map->type, name);
|
||||
return dso__find_symbol_by_name(map->dso, name);
|
||||
}
|
||||
|
||||
struct map *map__clone(struct map *from)
|
||||
@ -494,10 +492,7 @@ static void maps__init(struct maps *maps)
|
||||
|
||||
void map_groups__init(struct map_groups *mg, struct machine *machine)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < MAP__NR_TYPES; ++i) {
|
||||
maps__init(&mg->maps[i]);
|
||||
}
|
||||
maps__init(&mg->maps);
|
||||
mg->machine = machine;
|
||||
refcount_set(&mg->refcnt, 1);
|
||||
}
|
||||
@ -525,22 +520,12 @@ static void maps__exit(struct maps *maps)
|
||||
|
||||
void map_groups__exit(struct map_groups *mg)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAP__NR_TYPES; ++i)
|
||||
maps__exit(&mg->maps[i]);
|
||||
maps__exit(&mg->maps);
|
||||
}
|
||||
|
||||
bool map_groups__empty(struct map_groups *mg)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAP__NR_TYPES; ++i) {
|
||||
if (maps__first(&mg->maps[i]))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return !maps__first(&mg->maps);
|
||||
}
|
||||
|
||||
struct map_groups *map_groups__new(struct machine *machine)
|
||||
@ -566,10 +551,9 @@ void map_groups__put(struct map_groups *mg)
|
||||
}
|
||||
|
||||
struct symbol *map_groups__find_symbol(struct map_groups *mg,
|
||||
enum map_type type, u64 addr,
|
||||
struct map **mapp)
|
||||
u64 addr, struct map **mapp)
|
||||
{
|
||||
struct map *map = map_groups__find(mg, type, addr);
|
||||
struct map *map = map_groups__find(mg, addr);
|
||||
|
||||
/* Ensure map is loaded before using map->map_ip */
|
||||
if (map != NULL && map__load(map) >= 0) {
|
||||
@ -608,13 +592,10 @@ out:
|
||||
}
|
||||
|
||||
struct symbol *map_groups__find_symbol_by_name(struct map_groups *mg,
|
||||
enum map_type type,
|
||||
const char *name,
|
||||
struct map **mapp)
|
||||
{
|
||||
struct symbol *sym = maps__find_symbol_by_name(&mg->maps[type], name, mapp);
|
||||
|
||||
return sym;
|
||||
return maps__find_symbol_by_name(&mg->maps, name, mapp);
|
||||
}
|
||||
|
||||
int map_groups__find_ams(struct addr_map_symbol *ams)
|
||||
@ -622,8 +603,7 @@ int map_groups__find_ams(struct addr_map_symbol *ams)
|
||||
if (ams->addr < ams->map->start || ams->addr >= ams->map->end) {
|
||||
if (ams->map->groups == NULL)
|
||||
return -1;
|
||||
ams->map = map_groups__find(ams->map->groups, ams->map->type,
|
||||
ams->addr);
|
||||
ams->map = map_groups__find(ams->map->groups, ams->addr);
|
||||
if (ams->map == NULL)
|
||||
return -1;
|
||||
}
|
||||
@ -646,7 +626,7 @@ static size_t maps__fprintf(struct maps *maps, FILE *fp)
|
||||
printed += fprintf(fp, "Map:");
|
||||
printed += map__fprintf(pos, fp);
|
||||
if (verbose > 2) {
|
||||
printed += dso__fprintf(pos->dso, pos->type, fp);
|
||||
printed += dso__fprintf(pos->dso, fp);
|
||||
printed += fprintf(fp, "--\n");
|
||||
}
|
||||
}
|
||||
@ -656,24 +636,14 @@ static size_t maps__fprintf(struct maps *maps, FILE *fp)
|
||||
return printed;
|
||||
}
|
||||
|
||||
size_t __map_groups__fprintf_maps(struct map_groups *mg, enum map_type type,
|
||||
FILE *fp)
|
||||
{
|
||||
size_t printed = fprintf(fp, "%s:\n", map_type__name[type]);
|
||||
return printed += maps__fprintf(&mg->maps[type], fp);
|
||||
}
|
||||
|
||||
size_t map_groups__fprintf(struct map_groups *mg, FILE *fp)
|
||||
{
|
||||
size_t printed = 0, i;
|
||||
for (i = 0; i < MAP__NR_TYPES; ++i)
|
||||
printed += __map_groups__fprintf_maps(mg, i, fp);
|
||||
return printed;
|
||||
return maps__fprintf(&mg->maps, fp);
|
||||
}
|
||||
|
||||
static void __map_groups__insert(struct map_groups *mg, struct map *map)
|
||||
{
|
||||
__maps__insert(&mg->maps[map->type], map);
|
||||
__maps__insert(&mg->maps, map);
|
||||
map->groups = mg;
|
||||
}
|
||||
|
||||
@ -758,19 +728,18 @@ out:
|
||||
int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map,
|
||||
FILE *fp)
|
||||
{
|
||||
return maps__fixup_overlappings(&mg->maps[map->type], map, fp);
|
||||
return maps__fixup_overlappings(&mg->maps, map, fp);
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX This should not really _copy_ te maps, but refcount them.
|
||||
*/
|
||||
int map_groups__clone(struct thread *thread,
|
||||
struct map_groups *parent, enum map_type type)
|
||||
int map_groups__clone(struct thread *thread, struct map_groups *parent)
|
||||
{
|
||||
struct map_groups *mg = thread->mg;
|
||||
int err = -ENOMEM;
|
||||
struct map *map;
|
||||
struct maps *maps = &parent->maps[type];
|
||||
struct maps *maps = &parent->maps;
|
||||
|
||||
down_read(&maps->lock);
|
||||
|
||||
|
@ -12,15 +12,6 @@
|
||||
#include <linux/types.h>
|
||||
#include "rwsem.h"
|
||||
|
||||
enum map_type {
|
||||
MAP__FUNCTION = 0,
|
||||
MAP__VARIABLE,
|
||||
};
|
||||
|
||||
#define MAP__NR_TYPES (MAP__VARIABLE + 1)
|
||||
|
||||
extern const char *map_type__name[MAP__NR_TYPES];
|
||||
|
||||
struct dso;
|
||||
struct ip_callchain;
|
||||
struct ref_reloc_sym;
|
||||
@ -35,7 +26,6 @@ struct map {
|
||||
};
|
||||
u64 start;
|
||||
u64 end;
|
||||
u8 /* enum map_type */ type;
|
||||
bool erange_warned;
|
||||
u32 priv;
|
||||
u32 prot;
|
||||
@ -67,7 +57,7 @@ struct maps {
|
||||
};
|
||||
|
||||
struct map_groups {
|
||||
struct maps maps[MAP__NR_TYPES];
|
||||
struct maps maps;
|
||||
struct machine *machine;
|
||||
refcount_t refcnt;
|
||||
};
|
||||
@ -125,7 +115,7 @@ struct thread;
|
||||
* Note: caller must ensure map->dso is not NULL (map is loaded).
|
||||
*/
|
||||
#define map__for_each_symbol(map, pos, n) \
|
||||
dso__for_each_symbol(map->dso, pos, n, map->type)
|
||||
dso__for_each_symbol(map->dso, pos, n)
|
||||
|
||||
/* map__for_each_symbol_with_name - iterate over the symbols in the given map
|
||||
* that have the given name
|
||||
@ -144,13 +134,13 @@ struct thread;
|
||||
#define map__for_each_symbol_by_name(map, sym_name, pos) \
|
||||
__map__for_each_symbol_by_name(map, sym_name, (pos))
|
||||
|
||||
void map__init(struct map *map, enum map_type type,
|
||||
void map__init(struct map *map,
|
||||
u64 start, u64 end, u64 pgoff, struct dso *dso);
|
||||
struct map *map__new(struct machine *machine, u64 start, u64 len,
|
||||
u64 pgoff, u32 d_maj, u32 d_min, u64 ino,
|
||||
u64 ino_gen, u32 prot, u32 flags,
|
||||
char *filename, enum map_type type, struct thread *thread);
|
||||
struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
|
||||
char *filename, struct thread *thread);
|
||||
struct map *map__new2(u64 start, struct dso *dso);
|
||||
void map__delete(struct map *map);
|
||||
struct map *map__clone(struct map *map);
|
||||
|
||||
@ -185,8 +175,6 @@ void map__fixup_end(struct map *map);
|
||||
|
||||
void map__reloc_vmlinux(struct map *map);
|
||||
|
||||
size_t __map_groups__fprintf_maps(struct map_groups *mg, enum map_type type,
|
||||
FILE *fp);
|
||||
void maps__insert(struct maps *maps, struct map *map);
|
||||
void maps__remove(struct maps *maps, struct map *map);
|
||||
struct map *maps__find(struct maps *maps, u64 addr);
|
||||
@ -197,34 +185,29 @@ struct symbol *maps__find_symbol_by_name(struct maps *maps, const char *name,
|
||||
void map_groups__init(struct map_groups *mg, struct machine *machine);
|
||||
void map_groups__exit(struct map_groups *mg);
|
||||
int map_groups__clone(struct thread *thread,
|
||||
struct map_groups *parent, enum map_type type);
|
||||
struct map_groups *parent);
|
||||
size_t map_groups__fprintf(struct map_groups *mg, FILE *fp);
|
||||
|
||||
int maps__set_kallsyms_ref_reloc_sym(struct map **maps, const char *symbol_name,
|
||||
u64 addr);
|
||||
int map__set_kallsyms_ref_reloc_sym(struct map *map, const char *symbol_name,
|
||||
u64 addr);
|
||||
|
||||
static inline void map_groups__insert(struct map_groups *mg, struct map *map)
|
||||
{
|
||||
maps__insert(&mg->maps[map->type], map);
|
||||
maps__insert(&mg->maps, map);
|
||||
map->groups = mg;
|
||||
}
|
||||
|
||||
static inline void map_groups__remove(struct map_groups *mg, struct map *map)
|
||||
{
|
||||
maps__remove(&mg->maps[map->type], map);
|
||||
maps__remove(&mg->maps, map);
|
||||
}
|
||||
|
||||
static inline struct map *map_groups__find(struct map_groups *mg,
|
||||
enum map_type type, u64 addr)
|
||||
static inline struct map *map_groups__find(struct map_groups *mg, u64 addr)
|
||||
{
|
||||
return maps__find(&mg->maps[type], addr);
|
||||
return maps__find(&mg->maps, addr);
|
||||
}
|
||||
|
||||
static inline struct map *map_groups__first(struct map_groups *mg,
|
||||
enum map_type type)
|
||||
{
|
||||
return maps__first(&mg->maps[type]);
|
||||
}
|
||||
struct map *map_groups__first(struct map_groups *mg);
|
||||
|
||||
static inline struct map *map_groups__next(struct map *map)
|
||||
{
|
||||
@ -232,11 +215,9 @@ static inline struct map *map_groups__next(struct map *map)
|
||||
}
|
||||
|
||||
struct symbol *map_groups__find_symbol(struct map_groups *mg,
|
||||
enum map_type type, u64 addr,
|
||||
struct map **mapp);
|
||||
u64 addr, struct map **mapp);
|
||||
|
||||
struct symbol *map_groups__find_symbol_by_name(struct map_groups *mg,
|
||||
enum map_type type,
|
||||
const char *name,
|
||||
struct map **mapp);
|
||||
|
||||
@ -244,18 +225,10 @@ struct addr_map_symbol;
|
||||
|
||||
int map_groups__find_ams(struct addr_map_symbol *ams);
|
||||
|
||||
static inline
|
||||
struct symbol *map_groups__find_function_by_name(struct map_groups *mg,
|
||||
const char *name, struct map **mapp)
|
||||
{
|
||||
return map_groups__find_symbol_by_name(mg, MAP__FUNCTION, name, mapp);
|
||||
}
|
||||
|
||||
int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map,
|
||||
FILE *fp);
|
||||
|
||||
struct map *map_groups__find_by_name(struct map_groups *mg,
|
||||
enum map_type type, const char *name);
|
||||
struct map *map_groups__find_by_name(struct map_groups *mg, const char *name);
|
||||
|
||||
bool __map__is_kernel(const struct map *map);
|
||||
|
||||
@ -264,4 +237,6 @@ static inline bool __map__is_kmodule(const struct map *map)
|
||||
return !__map__is_kernel(map);
|
||||
}
|
||||
|
||||
bool map__has_symbols(const struct map *map);
|
||||
|
||||
#endif /* __PERF_MAP_H */
|
||||
|
@ -111,17 +111,6 @@ void exit_probe_symbol_maps(void)
|
||||
symbol__exit();
|
||||
}
|
||||
|
||||
static struct symbol *__find_kernel_function_by_name(const char *name,
|
||||
struct map **mapp)
|
||||
{
|
||||
return machine__find_kernel_function_by_name(host_machine, name, mapp);
|
||||
}
|
||||
|
||||
static struct symbol *__find_kernel_function(u64 addr, struct map **mapp)
|
||||
{
|
||||
return machine__find_kernel_function(host_machine, addr, mapp);
|
||||
}
|
||||
|
||||
static struct ref_reloc_sym *kernel_get_ref_reloc_sym(void)
|
||||
{
|
||||
/* kmap->ref_reloc_sym should be set if host_machine is initialized */
|
||||
@ -149,7 +138,7 @@ static int kernel_get_symbol_address_by_name(const char *name, u64 *addr,
|
||||
if (reloc_sym && strcmp(name, reloc_sym->name) == 0)
|
||||
*addr = (reloc) ? reloc_sym->addr : reloc_sym->unrelocated_addr;
|
||||
else {
|
||||
sym = __find_kernel_function_by_name(name, &map);
|
||||
sym = machine__find_kernel_symbol_by_name(host_machine, name, &map);
|
||||
if (!sym)
|
||||
return -ENOENT;
|
||||
*addr = map->unmap_ip(map, sym->start) -
|
||||
@ -161,8 +150,7 @@ static int kernel_get_symbol_address_by_name(const char *name, u64 *addr,
|
||||
|
||||
static struct map *kernel_get_module_map(const char *module)
|
||||
{
|
||||
struct map_groups *grp = &host_machine->kmaps;
|
||||
struct maps *maps = &grp->maps[MAP__FUNCTION];
|
||||
struct maps *maps = machine__kernel_maps(host_machine);
|
||||
struct map *pos;
|
||||
|
||||
/* A file path -- this is an offline module */
|
||||
@ -341,7 +329,7 @@ static int kernel_get_module_dso(const char *module, struct dso **pdso)
|
||||
char module_name[128];
|
||||
|
||||
snprintf(module_name, sizeof(module_name), "[%s]", module);
|
||||
map = map_groups__find_by_name(&host_machine->kmaps, MAP__FUNCTION, module_name);
|
||||
map = map_groups__find_by_name(&host_machine->kmaps, module_name);
|
||||
if (map) {
|
||||
dso = map->dso;
|
||||
goto found;
|
||||
@ -2098,7 +2086,7 @@ static int find_perf_probe_point_from_map(struct probe_trace_point *tp,
|
||||
}
|
||||
if (addr) {
|
||||
addr += tp->offset;
|
||||
sym = __find_kernel_function(addr, &map);
|
||||
sym = machine__find_kernel_symbol(host_machine, addr, &map);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3504,19 +3492,18 @@ int show_available_funcs(const char *target, struct nsinfo *nsi,
|
||||
(target) ? : "kernel");
|
||||
goto end;
|
||||
}
|
||||
if (!dso__sorted_by_name(map->dso, map->type))
|
||||
dso__sort_by_name(map->dso, map->type);
|
||||
if (!dso__sorted_by_name(map->dso))
|
||||
dso__sort_by_name(map->dso);
|
||||
|
||||
/* Show all (filtered) symbols */
|
||||
setup_pager();
|
||||
|
||||
for (nd = rb_first(&map->dso->symbol_names[map->type]); nd; nd = rb_next(nd)) {
|
||||
for (nd = rb_first(&map->dso->symbol_names); nd; nd = rb_next(nd)) {
|
||||
struct symbol_name_rb_node *pos = rb_entry(nd, struct symbol_name_rb_node, rb_node);
|
||||
|
||||
if (strfilter__compare(_filter, pos->sym.name))
|
||||
printf("%s\n", pos->sym.name);
|
||||
}
|
||||
|
||||
}
|
||||
end:
|
||||
map__put(map);
|
||||
exit_probe_symbol_maps();
|
||||
|
@ -1973,12 +1973,11 @@ bool perf_session__has_traces(struct perf_session *session, const char *msg)
|
||||
return false;
|
||||
}
|
||||
|
||||
int maps__set_kallsyms_ref_reloc_sym(struct map **maps,
|
||||
const char *symbol_name, u64 addr)
|
||||
int map__set_kallsyms_ref_reloc_sym(struct map *map, const char *symbol_name, u64 addr)
|
||||
{
|
||||
char *bracket;
|
||||
int i;
|
||||
struct ref_reloc_sym *ref;
|
||||
struct kmap *kmap;
|
||||
|
||||
ref = zalloc(sizeof(struct ref_reloc_sym));
|
||||
if (ref == NULL)
|
||||
@ -1996,13 +1995,9 @@ int maps__set_kallsyms_ref_reloc_sym(struct map **maps,
|
||||
|
||||
ref->addr = addr;
|
||||
|
||||
for (i = 0; i < MAP__NR_TYPES; ++i) {
|
||||
struct kmap *kmap = map__kmap(maps[i]);
|
||||
|
||||
if (!kmap)
|
||||
continue;
|
||||
kmap = map__kmap(map);
|
||||
if (kmap)
|
||||
kmap->ref_reloc_sym = ref;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
#include <regex.h>
|
||||
#include <sys/mman.h>
|
||||
#include <linux/mman.h>
|
||||
#include "sort.h"
|
||||
#include "hist.h"
|
||||
#include "comm.h"
|
||||
@ -282,7 +282,7 @@ static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
|
||||
|
||||
ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", level);
|
||||
if (sym && map) {
|
||||
if (map->type == MAP__VARIABLE) {
|
||||
if (sym->type == STT_OBJECT) {
|
||||
ret += repsep_snprintf(bf + ret, size - ret, "%s", sym->name);
|
||||
ret += repsep_snprintf(bf + ret, size - ret, "+0x%llx",
|
||||
ip - map->unmap_ip(map, sym->start));
|
||||
@ -1211,7 +1211,7 @@ static int hist_entry__dcacheline_snprintf(struct hist_entry *he, char *bf,
|
||||
|
||||
/* print [s] for shared data mmaps */
|
||||
if ((he->cpumode != PERF_RECORD_MISC_KERNEL) &&
|
||||
map && (map->type == MAP__VARIABLE) &&
|
||||
map && !(map->prot & PROT_EXEC) &&
|
||||
(map->flags & MAP_SHARED) &&
|
||||
(map->maj || map->min || map->ino ||
|
||||
map->ino_generation))
|
||||
|
@ -103,6 +103,7 @@ static struct symbol *new_inline_sym(struct dso *dso,
|
||||
inline_sym = symbol__new(base_sym ? base_sym->start : 0,
|
||||
base_sym ? base_sym->end : 0,
|
||||
base_sym ? base_sym->binding : 0,
|
||||
base_sym ? base_sym->type : 0,
|
||||
funcname);
|
||||
if (inline_sym)
|
||||
inline_sym->inlined = 1;
|
||||
|
@ -7,8 +7,7 @@
|
||||
#include "xyarray.h"
|
||||
#include "rblist.h"
|
||||
|
||||
struct stats
|
||||
{
|
||||
struct stats {
|
||||
double n, mean, M2;
|
||||
u64 max, min;
|
||||
};
|
||||
|
@ -114,16 +114,9 @@ static inline int elf_sym__is_label(const GElf_Sym *sym)
|
||||
sym->st_shndx != SHN_ABS;
|
||||
}
|
||||
|
||||
static bool elf_sym__is_a(GElf_Sym *sym, enum map_type type)
|
||||
static bool elf_sym__filter(GElf_Sym *sym)
|
||||
{
|
||||
switch (type) {
|
||||
case MAP__FUNCTION:
|
||||
return elf_sym__is_function(sym);
|
||||
case MAP__VARIABLE:
|
||||
return elf_sym__is_object(sym);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return elf_sym__is_function(sym) || elf_sym__is_object(sym);
|
||||
}
|
||||
|
||||
static inline const char *elf_sym__name(const GElf_Sym *sym,
|
||||
@ -150,17 +143,10 @@ static inline bool elf_sec__is_data(const GElf_Shdr *shdr,
|
||||
return strstr(elf_sec__name(shdr, secstrs), "data") != NULL;
|
||||
}
|
||||
|
||||
static bool elf_sec__is_a(GElf_Shdr *shdr, Elf_Data *secstrs,
|
||||
enum map_type type)
|
||||
static bool elf_sec__filter(GElf_Shdr *shdr, Elf_Data *secstrs)
|
||||
{
|
||||
switch (type) {
|
||||
case MAP__FUNCTION:
|
||||
return elf_sec__is_text(shdr, secstrs);
|
||||
case MAP__VARIABLE:
|
||||
return elf_sec__is_data(shdr, secstrs);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return elf_sec__is_text(shdr, secstrs) ||
|
||||
elf_sec__is_data(shdr, secstrs);
|
||||
}
|
||||
|
||||
static size_t elf_addr_to_index(Elf *elf, GElf_Addr addr)
|
||||
@ -256,7 +242,7 @@ static char *demangle_sym(struct dso *dso, int kmodule, const char *elf_name)
|
||||
* And always look at the original dso, not at debuginfo packages, that
|
||||
* have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS).
|
||||
*/
|
||||
int dso__synthesize_plt_symbols(struct dso *dso, struct symsrc *ss, struct map *map)
|
||||
int dso__synthesize_plt_symbols(struct dso *dso, struct symsrc *ss)
|
||||
{
|
||||
uint32_t nr_rel_entries, idx;
|
||||
GElf_Sym sym;
|
||||
@ -364,12 +350,12 @@ int dso__synthesize_plt_symbols(struct dso *dso, struct symsrc *ss, struct map *
|
||||
free(demangled);
|
||||
|
||||
f = symbol__new(plt_offset, plt_entry_size,
|
||||
STB_GLOBAL, sympltname);
|
||||
STB_GLOBAL, STT_FUNC, sympltname);
|
||||
if (!f)
|
||||
goto out_elf_end;
|
||||
|
||||
plt_offset += plt_entry_size;
|
||||
symbols__insert(&dso->symbols[map->type], f);
|
||||
symbols__insert(&dso->symbols, f);
|
||||
++nr;
|
||||
}
|
||||
} else if (shdr_rel_plt.sh_type == SHT_REL) {
|
||||
@ -390,12 +376,12 @@ int dso__synthesize_plt_symbols(struct dso *dso, struct symsrc *ss, struct map *
|
||||
free(demangled);
|
||||
|
||||
f = symbol__new(plt_offset, plt_entry_size,
|
||||
STB_GLOBAL, sympltname);
|
||||
STB_GLOBAL, STT_FUNC, sympltname);
|
||||
if (!f)
|
||||
goto out_elf_end;
|
||||
|
||||
plt_offset += plt_entry_size;
|
||||
symbols__insert(&dso->symbols[map->type], f);
|
||||
symbols__insert(&dso->symbols, f);
|
||||
++nr;
|
||||
}
|
||||
}
|
||||
@ -811,6 +797,110 @@ static u64 ref_reloc(struct kmap *kmap)
|
||||
void __weak arch__sym_update(struct symbol *s __maybe_unused,
|
||||
GElf_Sym *sym __maybe_unused) { }
|
||||
|
||||
static int dso__process_kernel_symbol(struct dso *dso, struct map *map,
|
||||
GElf_Sym *sym, GElf_Shdr *shdr,
|
||||
struct map_groups *kmaps, struct kmap *kmap,
|
||||
struct dso **curr_dsop, struct map **curr_mapp,
|
||||
const char *section_name,
|
||||
bool adjust_kernel_syms, bool kmodule, bool *remap_kernel)
|
||||
{
|
||||
struct dso *curr_dso = *curr_dsop;
|
||||
struct map *curr_map;
|
||||
char dso_name[PATH_MAX];
|
||||
|
||||
/* Adjust symbol to map to file offset */
|
||||
if (adjust_kernel_syms)
|
||||
sym->st_value -= shdr->sh_addr - shdr->sh_offset;
|
||||
|
||||
if (strcmp(section_name, (curr_dso->short_name + dso->short_name_len)) == 0)
|
||||
return 0;
|
||||
|
||||
if (strcmp(section_name, ".text") == 0) {
|
||||
/*
|
||||
* The initial kernel mapping is based on
|
||||
* kallsyms and identity maps. Overwrite it to
|
||||
* map to the kernel dso.
|
||||
*/
|
||||
if (*remap_kernel && dso->kernel) {
|
||||
*remap_kernel = false;
|
||||
map->start = shdr->sh_addr + ref_reloc(kmap);
|
||||
map->end = map->start + shdr->sh_size;
|
||||
map->pgoff = shdr->sh_offset;
|
||||
map->map_ip = map__map_ip;
|
||||
map->unmap_ip = map__unmap_ip;
|
||||
/* Ensure maps are correctly ordered */
|
||||
if (kmaps) {
|
||||
map__get(map);
|
||||
map_groups__remove(kmaps, map);
|
||||
map_groups__insert(kmaps, map);
|
||||
map__put(map);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The initial module mapping is based on
|
||||
* /proc/modules mapped to offset zero.
|
||||
* Overwrite it to map to the module dso.
|
||||
*/
|
||||
if (*remap_kernel && kmodule) {
|
||||
*remap_kernel = false;
|
||||
map->pgoff = shdr->sh_offset;
|
||||
}
|
||||
|
||||
*curr_mapp = map;
|
||||
*curr_dsop = dso;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!kmap)
|
||||
return 0;
|
||||
|
||||
snprintf(dso_name, sizeof(dso_name), "%s%s", dso->short_name, section_name);
|
||||
|
||||
curr_map = map_groups__find_by_name(kmaps, dso_name);
|
||||
if (curr_map == NULL) {
|
||||
u64 start = sym->st_value;
|
||||
|
||||
if (kmodule)
|
||||
start += map->start + shdr->sh_offset;
|
||||
|
||||
curr_dso = dso__new(dso_name);
|
||||
if (curr_dso == NULL)
|
||||
return -1;
|
||||
curr_dso->kernel = dso->kernel;
|
||||
curr_dso->long_name = dso->long_name;
|
||||
curr_dso->long_name_len = dso->long_name_len;
|
||||
curr_map = map__new2(start, curr_dso);
|
||||
dso__put(curr_dso);
|
||||
if (curr_map == NULL)
|
||||
return -1;
|
||||
|
||||
if (adjust_kernel_syms) {
|
||||
curr_map->start = shdr->sh_addr + ref_reloc(kmap);
|
||||
curr_map->end = curr_map->start + shdr->sh_size;
|
||||
curr_map->pgoff = shdr->sh_offset;
|
||||
} else {
|
||||
curr_map->map_ip = curr_map->unmap_ip = identity__map_ip;
|
||||
}
|
||||
curr_dso->symtab_type = dso->symtab_type;
|
||||
map_groups__insert(kmaps, curr_map);
|
||||
/*
|
||||
* Add it before we drop the referece to curr_map, i.e. while
|
||||
* we still are sure to have a reference to this DSO via
|
||||
* *curr_map->dso.
|
||||
*/
|
||||
dsos__add(&map->groups->machine->dsos, curr_dso);
|
||||
/* kmaps already got it */
|
||||
map__put(curr_map);
|
||||
dso__set_loaded(curr_dso);
|
||||
*curr_mapp = curr_map;
|
||||
*curr_dsop = curr_dso;
|
||||
} else
|
||||
*curr_dsop = curr_map->dso;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss,
|
||||
struct symsrc *runtime_ss, int kmodule)
|
||||
{
|
||||
@ -844,7 +934,7 @@ int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss,
|
||||
* have the wrong values for the dso maps, so remove them.
|
||||
*/
|
||||
if (kmodule && syms_ss->symtab)
|
||||
symbols__delete(&dso->symbols[map->type]);
|
||||
symbols__delete(&dso->symbols);
|
||||
|
||||
if (!syms_ss->symtab) {
|
||||
/*
|
||||
@ -921,10 +1011,10 @@ int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss,
|
||||
|
||||
dso->adjust_symbols = runtime_ss->adjust_symbols || ref_reloc(kmap);
|
||||
/*
|
||||
* Initial kernel and module mappings do not map to the dso. For
|
||||
* function mappings, flag the fixups.
|
||||
* Initial kernel and module mappings do not map to the dso.
|
||||
* Flag the fixups.
|
||||
*/
|
||||
if (map->type == MAP__FUNCTION && (dso->kernel || kmodule)) {
|
||||
if (dso->kernel || kmodule) {
|
||||
remap_kernel = true;
|
||||
adjust_kernel_syms = dso->adjust_symbols;
|
||||
}
|
||||
@ -936,7 +1026,7 @@ int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss,
|
||||
const char *section_name;
|
||||
bool used_opd = false;
|
||||
|
||||
if (!is_label && !elf_sym__is_a(&sym, map->type))
|
||||
if (!is_label && !elf_sym__filter(&sym))
|
||||
continue;
|
||||
|
||||
/* Reject ARM ELF "mapping symbols": these aren't unique and
|
||||
@ -974,7 +1064,7 @@ int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss,
|
||||
|
||||
gelf_getshdr(sec, &shdr);
|
||||
|
||||
if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type))
|
||||
if (is_label && !elf_sec__filter(&shdr, secstrs))
|
||||
continue;
|
||||
|
||||
section_name = elf_sec__name(&shdr, secstrs);
|
||||
@ -982,134 +1072,37 @@ int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss,
|
||||
/* On ARM, symbols for thumb functions have 1 added to
|
||||
* the symbol address as a flag - remove it */
|
||||
if ((ehdr.e_machine == EM_ARM) &&
|
||||
(map->type == MAP__FUNCTION) &&
|
||||
(GELF_ST_TYPE(sym.st_info) == STT_FUNC) &&
|
||||
(sym.st_value & 1))
|
||||
--sym.st_value;
|
||||
|
||||
if (dso->kernel || kmodule) {
|
||||
char dso_name[PATH_MAX];
|
||||
|
||||
/* Adjust symbol to map to file offset */
|
||||
if (adjust_kernel_syms)
|
||||
sym.st_value -= shdr.sh_addr - shdr.sh_offset;
|
||||
|
||||
if (strcmp(section_name,
|
||||
(curr_dso->short_name +
|
||||
dso->short_name_len)) == 0)
|
||||
goto new_symbol;
|
||||
|
||||
if (strcmp(section_name, ".text") == 0) {
|
||||
/*
|
||||
* The initial kernel mapping is based on
|
||||
* kallsyms and identity maps. Overwrite it to
|
||||
* map to the kernel dso.
|
||||
*/
|
||||
if (remap_kernel && dso->kernel) {
|
||||
remap_kernel = false;
|
||||
map->start = shdr.sh_addr +
|
||||
ref_reloc(kmap);
|
||||
map->end = map->start + shdr.sh_size;
|
||||
map->pgoff = shdr.sh_offset;
|
||||
map->map_ip = map__map_ip;
|
||||
map->unmap_ip = map__unmap_ip;
|
||||
/* Ensure maps are correctly ordered */
|
||||
if (kmaps) {
|
||||
map__get(map);
|
||||
map_groups__remove(kmaps, map);
|
||||
map_groups__insert(kmaps, map);
|
||||
map__put(map);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The initial module mapping is based on
|
||||
* /proc/modules mapped to offset zero.
|
||||
* Overwrite it to map to the module dso.
|
||||
*/
|
||||
if (remap_kernel && kmodule) {
|
||||
remap_kernel = false;
|
||||
map->pgoff = shdr.sh_offset;
|
||||
}
|
||||
|
||||
curr_map = map;
|
||||
curr_dso = dso;
|
||||
goto new_symbol;
|
||||
}
|
||||
|
||||
if (!kmap)
|
||||
goto new_symbol;
|
||||
|
||||
snprintf(dso_name, sizeof(dso_name),
|
||||
"%s%s", dso->short_name, section_name);
|
||||
|
||||
curr_map = map_groups__find_by_name(kmaps, map->type, dso_name);
|
||||
if (curr_map == NULL) {
|
||||
u64 start = sym.st_value;
|
||||
|
||||
if (kmodule)
|
||||
start += map->start + shdr.sh_offset;
|
||||
|
||||
curr_dso = dso__new(dso_name);
|
||||
if (curr_dso == NULL)
|
||||
goto out_elf_end;
|
||||
curr_dso->kernel = dso->kernel;
|
||||
curr_dso->long_name = dso->long_name;
|
||||
curr_dso->long_name_len = dso->long_name_len;
|
||||
curr_map = map__new2(start, curr_dso,
|
||||
map->type);
|
||||
dso__put(curr_dso);
|
||||
if (curr_map == NULL) {
|
||||
goto out_elf_end;
|
||||
}
|
||||
if (adjust_kernel_syms) {
|
||||
curr_map->start = shdr.sh_addr +
|
||||
ref_reloc(kmap);
|
||||
curr_map->end = curr_map->start +
|
||||
shdr.sh_size;
|
||||
curr_map->pgoff = shdr.sh_offset;
|
||||
} else {
|
||||
curr_map->map_ip = identity__map_ip;
|
||||
curr_map->unmap_ip = identity__map_ip;
|
||||
}
|
||||
curr_dso->symtab_type = dso->symtab_type;
|
||||
map_groups__insert(kmaps, curr_map);
|
||||
/*
|
||||
* Add it before we drop the referece to curr_map,
|
||||
* i.e. while we still are sure to have a reference
|
||||
* to this DSO via curr_map->dso.
|
||||
*/
|
||||
dsos__add(&map->groups->machine->dsos, curr_dso);
|
||||
/* kmaps already got it */
|
||||
map__put(curr_map);
|
||||
dso__set_loaded(curr_dso, map->type);
|
||||
} else
|
||||
curr_dso = curr_map->dso;
|
||||
|
||||
goto new_symbol;
|
||||
}
|
||||
|
||||
if ((used_opd && runtime_ss->adjust_symbols)
|
||||
|| (!used_opd && syms_ss->adjust_symbols)) {
|
||||
if (dso__process_kernel_symbol(dso, map, &sym, &shdr, kmaps, kmap, &curr_dso, &curr_map,
|
||||
section_name, adjust_kernel_syms, kmodule, &remap_kernel))
|
||||
goto out_elf_end;
|
||||
} else if ((used_opd && runtime_ss->adjust_symbols) ||
|
||||
(!used_opd && syms_ss->adjust_symbols)) {
|
||||
pr_debug4("%s: adjusting symbol: st_value: %#" PRIx64 " "
|
||||
"sh_addr: %#" PRIx64 " sh_offset: %#" PRIx64 "\n", __func__,
|
||||
(u64)sym.st_value, (u64)shdr.sh_addr,
|
||||
(u64)shdr.sh_offset);
|
||||
sym.st_value -= shdr.sh_addr - shdr.sh_offset;
|
||||
}
|
||||
new_symbol:
|
||||
|
||||
demangled = demangle_sym(dso, kmodule, elf_name);
|
||||
if (demangled != NULL)
|
||||
elf_name = demangled;
|
||||
|
||||
f = symbol__new(sym.st_value, sym.st_size,
|
||||
GELF_ST_BIND(sym.st_info), elf_name);
|
||||
GELF_ST_BIND(sym.st_info),
|
||||
GELF_ST_TYPE(sym.st_info), elf_name);
|
||||
free(demangled);
|
||||
if (!f)
|
||||
goto out_elf_end;
|
||||
|
||||
arch__sym_update(f, &sym);
|
||||
|
||||
__symbols__insert(&curr_dso->symbols[curr_map->type], f, dso->kernel);
|
||||
__symbols__insert(&curr_dso->symbols, f, dso->kernel);
|
||||
nr++;
|
||||
}
|
||||
|
||||
@ -1117,14 +1110,14 @@ new_symbol:
|
||||
* For misannotated, zeroed, ASM function sizes.
|
||||
*/
|
||||
if (nr > 0) {
|
||||
symbols__fixup_end(&dso->symbols[map->type]);
|
||||
symbols__fixup_duplicate(&dso->symbols[map->type]);
|
||||
symbols__fixup_end(&dso->symbols);
|
||||
symbols__fixup_duplicate(&dso->symbols);
|
||||
if (kmap) {
|
||||
/*
|
||||
* We need to fixup this here too because we create new
|
||||
* maps here, for things like vsyscall sections.
|
||||
*/
|
||||
__map_groups__fixup_end(kmaps, map->type);
|
||||
map_groups__fixup_end(kmaps);
|
||||
}
|
||||
}
|
||||
err = nr;
|
||||
@ -1413,7 +1406,7 @@ static int kcore_copy__process_kallsyms(void *arg, const char *name, char type,
|
||||
{
|
||||
struct kcore_copy_info *kci = arg;
|
||||
|
||||
if (!symbol_type__is_a(type, MAP__FUNCTION))
|
||||
if (!kallsyms__is_function(type))
|
||||
return 0;
|
||||
|
||||
if (strchr(name, '[')) {
|
||||
|
@ -288,8 +288,7 @@ void symsrc__destroy(struct symsrc *ss)
|
||||
}
|
||||
|
||||
int dso__synthesize_plt_symbols(struct dso *dso __maybe_unused,
|
||||
struct symsrc *ss __maybe_unused,
|
||||
struct map *map __maybe_unused)
|
||||
struct symsrc *ss __maybe_unused)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mman.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/param.h>
|
||||
@ -70,18 +71,10 @@ static enum dso_binary_type binary_type_symtab[] = {
|
||||
|
||||
#define DSO_BINARY_TYPE__SYMTAB_CNT ARRAY_SIZE(binary_type_symtab)
|
||||
|
||||
bool symbol_type__is_a(char symbol_type, enum map_type map_type)
|
||||
static bool symbol_type__filter(char symbol_type)
|
||||
{
|
||||
symbol_type = toupper(symbol_type);
|
||||
|
||||
switch (map_type) {
|
||||
case MAP__FUNCTION:
|
||||
return symbol_type == 'T' || symbol_type == 'W';
|
||||
case MAP__VARIABLE:
|
||||
return symbol_type == 'D';
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return symbol_type == 'T' || symbol_type == 'W' || symbol_type == 'D';
|
||||
}
|
||||
|
||||
static int prefix_underscores_count(const char *str)
|
||||
@ -228,9 +221,9 @@ void symbols__fixup_end(struct rb_root *symbols)
|
||||
curr->end = roundup(curr->start, 4096) + 4096;
|
||||
}
|
||||
|
||||
void __map_groups__fixup_end(struct map_groups *mg, enum map_type type)
|
||||
void map_groups__fixup_end(struct map_groups *mg)
|
||||
{
|
||||
struct maps *maps = &mg->maps[type];
|
||||
struct maps *maps = &mg->maps;
|
||||
struct map *next, *curr;
|
||||
|
||||
down_write(&maps->lock);
|
||||
@ -256,7 +249,7 @@ out_unlock:
|
||||
up_write(&maps->lock);
|
||||
}
|
||||
|
||||
struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name)
|
||||
struct symbol *symbol__new(u64 start, u64 len, u8 binding, u8 type, const char *name)
|
||||
{
|
||||
size_t namelen = strlen(name) + 1;
|
||||
struct symbol *sym = calloc(1, (symbol_conf.priv_size +
|
||||
@ -274,6 +267,7 @@ struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name)
|
||||
|
||||
sym->start = start;
|
||||
sym->end = len ? start + len : start;
|
||||
sym->type = type;
|
||||
sym->binding = binding;
|
||||
sym->namelen = namelen - 1;
|
||||
|
||||
@ -484,45 +478,40 @@ static struct symbol *symbols__find_by_name(struct rb_root *symbols,
|
||||
|
||||
void dso__reset_find_symbol_cache(struct dso *dso)
|
||||
{
|
||||
enum map_type type;
|
||||
|
||||
for (type = MAP__FUNCTION; type <= MAP__VARIABLE; ++type) {
|
||||
dso->last_find_result[type].addr = 0;
|
||||
dso->last_find_result[type].symbol = NULL;
|
||||
}
|
||||
dso->last_find_result.addr = 0;
|
||||
dso->last_find_result.symbol = NULL;
|
||||
}
|
||||
|
||||
void dso__insert_symbol(struct dso *dso, enum map_type type, struct symbol *sym)
|
||||
void dso__insert_symbol(struct dso *dso, struct symbol *sym)
|
||||
{
|
||||
__symbols__insert(&dso->symbols[type], sym, dso->kernel);
|
||||
__symbols__insert(&dso->symbols, sym, dso->kernel);
|
||||
|
||||
/* update the symbol cache if necessary */
|
||||
if (dso->last_find_result[type].addr >= sym->start &&
|
||||
(dso->last_find_result[type].addr < sym->end ||
|
||||
if (dso->last_find_result.addr >= sym->start &&
|
||||
(dso->last_find_result.addr < sym->end ||
|
||||
sym->start == sym->end)) {
|
||||
dso->last_find_result[type].symbol = sym;
|
||||
dso->last_find_result.symbol = sym;
|
||||
}
|
||||
}
|
||||
|
||||
struct symbol *dso__find_symbol(struct dso *dso,
|
||||
enum map_type type, u64 addr)
|
||||
struct symbol *dso__find_symbol(struct dso *dso, u64 addr)
|
||||
{
|
||||
if (dso->last_find_result[type].addr != addr || dso->last_find_result[type].symbol == NULL) {
|
||||
dso->last_find_result[type].addr = addr;
|
||||
dso->last_find_result[type].symbol = symbols__find(&dso->symbols[type], addr);
|
||||
if (dso->last_find_result.addr != addr || dso->last_find_result.symbol == NULL) {
|
||||
dso->last_find_result.addr = addr;
|
||||
dso->last_find_result.symbol = symbols__find(&dso->symbols, addr);
|
||||
}
|
||||
|
||||
return dso->last_find_result[type].symbol;
|
||||
return dso->last_find_result.symbol;
|
||||
}
|
||||
|
||||
struct symbol *dso__first_symbol(struct dso *dso, enum map_type type)
|
||||
struct symbol *dso__first_symbol(struct dso *dso)
|
||||
{
|
||||
return symbols__first(&dso->symbols[type]);
|
||||
return symbols__first(&dso->symbols);
|
||||
}
|
||||
|
||||
struct symbol *dso__last_symbol(struct dso *dso, enum map_type type)
|
||||
struct symbol *dso__last_symbol(struct dso *dso)
|
||||
{
|
||||
return symbols__last(&dso->symbols[type]);
|
||||
return symbols__last(&dso->symbols);
|
||||
}
|
||||
|
||||
struct symbol *dso__next_symbol(struct symbol *sym)
|
||||
@ -539,24 +528,22 @@ struct symbol *symbol__next_by_name(struct symbol *sym)
|
||||
}
|
||||
|
||||
/*
|
||||
* Teturns first symbol that matched with @name.
|
||||
* Returns first symbol that matched with @name.
|
||||
*/
|
||||
struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,
|
||||
const char *name)
|
||||
struct symbol *dso__find_symbol_by_name(struct dso *dso, const char *name)
|
||||
{
|
||||
struct symbol *s = symbols__find_by_name(&dso->symbol_names[type], name,
|
||||
struct symbol *s = symbols__find_by_name(&dso->symbol_names, name,
|
||||
SYMBOL_TAG_INCLUDE__NONE);
|
||||
if (!s)
|
||||
s = symbols__find_by_name(&dso->symbol_names[type], name,
|
||||
s = symbols__find_by_name(&dso->symbol_names, name,
|
||||
SYMBOL_TAG_INCLUDE__DEFAULT_ONLY);
|
||||
return s;
|
||||
}
|
||||
|
||||
void dso__sort_by_name(struct dso *dso, enum map_type type)
|
||||
void dso__sort_by_name(struct dso *dso)
|
||||
{
|
||||
dso__set_sorted_by_name(dso, type);
|
||||
return symbols__sort_by_name(&dso->symbol_names[type],
|
||||
&dso->symbols[type]);
|
||||
dso__set_sorted_by_name(dso);
|
||||
return symbols__sort_by_name(&dso->symbol_names, &dso->symbols);
|
||||
}
|
||||
|
||||
int modules__parse(const char *filename, void *arg,
|
||||
@ -621,11 +608,6 @@ out:
|
||||
return err;
|
||||
}
|
||||
|
||||
struct process_kallsyms_args {
|
||||
struct map *map;
|
||||
struct dso *dso;
|
||||
};
|
||||
|
||||
/*
|
||||
* These are symbols in the kernel image, so make sure that
|
||||
* sym is from a kernel DSO.
|
||||
@ -661,10 +643,10 @@ static int map__process_kallsym_symbol(void *arg, const char *name,
|
||||
char type, u64 start)
|
||||
{
|
||||
struct symbol *sym;
|
||||
struct process_kallsyms_args *a = arg;
|
||||
struct rb_root *root = &a->dso->symbols[a->map->type];
|
||||
struct dso *dso = arg;
|
||||
struct rb_root *root = &dso->symbols;
|
||||
|
||||
if (!symbol_type__is_a(type, a->map->type))
|
||||
if (!symbol_type__filter(type))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
@ -672,7 +654,7 @@ static int map__process_kallsym_symbol(void *arg, const char *name,
|
||||
* symbols, setting length to 0, and rely on
|
||||
* symbols__fixup_end() to fix it up.
|
||||
*/
|
||||
sym = symbol__new(start, 0, kallsyms2elf_binding(type), name);
|
||||
sym = symbol__new(start, 0, kallsyms2elf_binding(type), kallsyms2elf_type(type), name);
|
||||
if (sym == NULL)
|
||||
return -ENOMEM;
|
||||
/*
|
||||
@ -689,21 +671,18 @@ static int map__process_kallsym_symbol(void *arg, const char *name,
|
||||
* so that we can in the next step set the symbol ->end address and then
|
||||
* call kernel_maps__split_kallsyms.
|
||||
*/
|
||||
static int dso__load_all_kallsyms(struct dso *dso, const char *filename,
|
||||
struct map *map)
|
||||
static int dso__load_all_kallsyms(struct dso *dso, const char *filename)
|
||||
{
|
||||
struct process_kallsyms_args args = { .map = map, .dso = dso, };
|
||||
return kallsyms__parse(filename, &args, map__process_kallsym_symbol);
|
||||
return kallsyms__parse(filename, dso, map__process_kallsym_symbol);
|
||||
}
|
||||
|
||||
static int dso__split_kallsyms_for_kcore(struct dso *dso, struct map *map)
|
||||
static int map_groups__split_kallsyms_for_kcore(struct map_groups *kmaps, struct dso *dso)
|
||||
{
|
||||
struct map_groups *kmaps = map__kmaps(map);
|
||||
struct map *curr_map;
|
||||
struct symbol *pos;
|
||||
int count = 0;
|
||||
struct rb_root old_root = dso->symbols[map->type];
|
||||
struct rb_root *root = &dso->symbols[map->type];
|
||||
struct rb_root old_root = dso->symbols;
|
||||
struct rb_root *root = &dso->symbols;
|
||||
struct rb_node *next = rb_first(root);
|
||||
|
||||
if (!kmaps)
|
||||
@ -723,7 +702,7 @@ static int dso__split_kallsyms_for_kcore(struct dso *dso, struct map *map)
|
||||
if (module)
|
||||
*module = '\0';
|
||||
|
||||
curr_map = map_groups__find(kmaps, map->type, pos->start);
|
||||
curr_map = map_groups__find(kmaps, pos->start);
|
||||
|
||||
if (!curr_map) {
|
||||
symbol__delete(pos);
|
||||
@ -733,7 +712,7 @@ static int dso__split_kallsyms_for_kcore(struct dso *dso, struct map *map)
|
||||
pos->start -= curr_map->start - curr_map->pgoff;
|
||||
if (pos->end)
|
||||
pos->end -= curr_map->start - curr_map->pgoff;
|
||||
symbols__insert(&curr_map->dso->symbols[curr_map->type], pos);
|
||||
symbols__insert(&curr_map->dso->symbols, pos);
|
||||
++count;
|
||||
}
|
||||
|
||||
@ -748,14 +727,14 @@ static int dso__split_kallsyms_for_kcore(struct dso *dso, struct map *map)
|
||||
* kernel range is broken in several maps, named [kernel].N, as we don't have
|
||||
* the original ELF section names vmlinux have.
|
||||
*/
|
||||
static int dso__split_kallsyms(struct dso *dso, struct map *map, u64 delta)
|
||||
static int map_groups__split_kallsyms(struct map_groups *kmaps, struct dso *dso, u64 delta,
|
||||
struct map *initial_map)
|
||||
{
|
||||
struct map_groups *kmaps = map__kmaps(map);
|
||||
struct machine *machine;
|
||||
struct map *curr_map = map;
|
||||
struct map *curr_map = initial_map;
|
||||
struct symbol *pos;
|
||||
int count = 0, moved = 0;
|
||||
struct rb_root *root = &dso->symbols[map->type];
|
||||
struct rb_root *root = &dso->symbols;
|
||||
struct rb_node *next = rb_first(root);
|
||||
int kernel_range = 0;
|
||||
|
||||
@ -778,7 +757,7 @@ static int dso__split_kallsyms(struct dso *dso, struct map *map, u64 delta)
|
||||
*module++ = '\0';
|
||||
|
||||
if (strcmp(curr_map->dso->short_name, module)) {
|
||||
if (curr_map != map &&
|
||||
if (curr_map != initial_map &&
|
||||
dso->kernel == DSO_TYPE_GUEST_KERNEL &&
|
||||
machine__is_default_guest(machine)) {
|
||||
/*
|
||||
@ -788,18 +767,16 @@ static int dso__split_kallsyms(struct dso *dso, struct map *map, u64 delta)
|
||||
* symbols are in its kmap. Mark it as
|
||||
* loaded.
|
||||
*/
|
||||
dso__set_loaded(curr_map->dso,
|
||||
curr_map->type);
|
||||
dso__set_loaded(curr_map->dso);
|
||||
}
|
||||
|
||||
curr_map = map_groups__find_by_name(kmaps,
|
||||
map->type, module);
|
||||
curr_map = map_groups__find_by_name(kmaps, module);
|
||||
if (curr_map == NULL) {
|
||||
pr_debug("%s/proc/{kallsyms,modules} "
|
||||
"inconsistency while looking "
|
||||
"for \"%s\" module!\n",
|
||||
machine->root_dir, module);
|
||||
curr_map = map;
|
||||
curr_map = initial_map;
|
||||
goto discard_symbol;
|
||||
}
|
||||
|
||||
@ -809,11 +786,11 @@ static int dso__split_kallsyms(struct dso *dso, struct map *map, u64 delta)
|
||||
}
|
||||
/*
|
||||
* So that we look just like we get from .ko files,
|
||||
* i.e. not prelinked, relative to map->start.
|
||||
* i.e. not prelinked, relative to initial_map->start.
|
||||
*/
|
||||
pos->start = curr_map->map_ip(curr_map, pos->start);
|
||||
pos->end = curr_map->map_ip(curr_map, pos->end);
|
||||
} else if (curr_map != map) {
|
||||
} else if (curr_map != initial_map) {
|
||||
char dso_name[PATH_MAX];
|
||||
struct dso *ndso;
|
||||
|
||||
@ -824,7 +801,7 @@ static int dso__split_kallsyms(struct dso *dso, struct map *map, u64 delta)
|
||||
}
|
||||
|
||||
if (count == 0) {
|
||||
curr_map = map;
|
||||
curr_map = initial_map;
|
||||
goto add_symbol;
|
||||
}
|
||||
|
||||
@ -843,7 +820,7 @@ static int dso__split_kallsyms(struct dso *dso, struct map *map, u64 delta)
|
||||
|
||||
ndso->kernel = dso->kernel;
|
||||
|
||||
curr_map = map__new2(pos->start, ndso, map->type);
|
||||
curr_map = map__new2(pos->start, ndso);
|
||||
if (curr_map == NULL) {
|
||||
dso__put(ndso);
|
||||
return -1;
|
||||
@ -858,9 +835,9 @@ static int dso__split_kallsyms(struct dso *dso, struct map *map, u64 delta)
|
||||
pos->end -= delta;
|
||||
}
|
||||
add_symbol:
|
||||
if (curr_map != map) {
|
||||
if (curr_map != initial_map) {
|
||||
rb_erase(&pos->rb_node, root);
|
||||
symbols__insert(&curr_map->dso->symbols[curr_map->type], pos);
|
||||
symbols__insert(&curr_map->dso->symbols, pos);
|
||||
++moved;
|
||||
} else
|
||||
++count;
|
||||
@ -871,10 +848,10 @@ discard_symbol:
|
||||
symbol__delete(pos);
|
||||
}
|
||||
|
||||
if (curr_map != map &&
|
||||
if (curr_map != initial_map &&
|
||||
dso->kernel == DSO_TYPE_GUEST_KERNEL &&
|
||||
machine__is_default_guest(kmaps->machine)) {
|
||||
dso__set_loaded(curr_map->dso, curr_map->type);
|
||||
dso__set_loaded(curr_map->dso);
|
||||
}
|
||||
|
||||
return count + moved;
|
||||
@ -1035,6 +1012,11 @@ out_delete_from:
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct map *map_groups__first(struct map_groups *mg)
|
||||
{
|
||||
return maps__first(&mg->maps);
|
||||
}
|
||||
|
||||
static int do_validate_kcore_modules(const char *filename, struct map *map,
|
||||
struct map_groups *kmaps)
|
||||
{
|
||||
@ -1046,7 +1028,7 @@ static int do_validate_kcore_modules(const char *filename, struct map *map,
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
old_map = map_groups__first(kmaps, map->type);
|
||||
old_map = map_groups__first(kmaps);
|
||||
while (old_map) {
|
||||
struct map *next = map_groups__next(old_map);
|
||||
struct module_info *mi;
|
||||
@ -1138,7 +1120,6 @@ static int validate_kcore_addresses(const char *kallsyms_filename,
|
||||
|
||||
struct kcore_mapfn_data {
|
||||
struct dso *dso;
|
||||
enum map_type type;
|
||||
struct list_head maps;
|
||||
};
|
||||
|
||||
@ -1147,7 +1128,7 @@ static int kcore_mapfn(u64 start, u64 len, u64 pgoff, void *data)
|
||||
struct kcore_mapfn_data *md = data;
|
||||
struct map *map;
|
||||
|
||||
map = map__new2(start, md->dso, md->type);
|
||||
map = map__new2(start, md->dso);
|
||||
if (map == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -1163,7 +1144,6 @@ static int dso__load_kcore(struct dso *dso, struct map *map,
|
||||
const char *kallsyms_filename)
|
||||
{
|
||||
struct map_groups *kmaps = map__kmaps(map);
|
||||
struct machine *machine;
|
||||
struct kcore_mapfn_data md;
|
||||
struct map *old_map, *new_map, *replacement_map = NULL;
|
||||
bool is_64_bit;
|
||||
@ -1174,10 +1154,8 @@ static int dso__load_kcore(struct dso *dso, struct map *map,
|
||||
if (!kmaps)
|
||||
return -EINVAL;
|
||||
|
||||
machine = kmaps->machine;
|
||||
|
||||
/* This function requires that the map is the kernel map */
|
||||
if (map != machine->vmlinux_maps[map->type])
|
||||
if (!__map__is_kernel(map))
|
||||
return -EINVAL;
|
||||
|
||||
if (!filename_from_kallsyms_filename(kcore_filename, "kcore",
|
||||
@ -1189,7 +1167,6 @@ static int dso__load_kcore(struct dso *dso, struct map *map,
|
||||
return -EINVAL;
|
||||
|
||||
md.dso = dso;
|
||||
md.type = map->type;
|
||||
INIT_LIST_HEAD(&md.maps);
|
||||
|
||||
fd = open(kcore_filename, O_RDONLY);
|
||||
@ -1200,7 +1177,7 @@ static int dso__load_kcore(struct dso *dso, struct map *map,
|
||||
}
|
||||
|
||||
/* Read new maps into temporary lists */
|
||||
err = file__read_maps(fd, md.type == MAP__FUNCTION, kcore_mapfn, &md,
|
||||
err = file__read_maps(fd, map->prot & PROT_EXEC, kcore_mapfn, &md,
|
||||
&is_64_bit);
|
||||
if (err)
|
||||
goto out_err;
|
||||
@ -1212,7 +1189,7 @@ static int dso__load_kcore(struct dso *dso, struct map *map,
|
||||
}
|
||||
|
||||
/* Remove old maps */
|
||||
old_map = map_groups__first(kmaps, map->type);
|
||||
old_map = map_groups__first(kmaps);
|
||||
while (old_map) {
|
||||
struct map *next = map_groups__next(old_map);
|
||||
|
||||
@ -1222,7 +1199,7 @@ static int dso__load_kcore(struct dso *dso, struct map *map,
|
||||
}
|
||||
|
||||
/* Find the kernel map using the first symbol */
|
||||
sym = dso__first_symbol(dso, map->type);
|
||||
sym = dso__first_symbol(dso);
|
||||
list_for_each_entry(new_map, &md.maps, node) {
|
||||
if (sym && sym->start >= new_map->start &&
|
||||
sym->start < new_map->end) {
|
||||
@ -1268,7 +1245,7 @@ static int dso__load_kcore(struct dso *dso, struct map *map,
|
||||
|
||||
close(fd);
|
||||
|
||||
if (map->type == MAP__FUNCTION)
|
||||
if (map->prot & PROT_EXEC)
|
||||
pr_debug("Using %s for kernel object code\n", kcore_filename);
|
||||
else
|
||||
pr_debug("Using %s for kernel data\n", kcore_filename);
|
||||
@ -1289,14 +1266,10 @@ out_err:
|
||||
* If the kernel is relocated at boot time, kallsyms won't match. Compute the
|
||||
* delta based on the relocation reference symbol.
|
||||
*/
|
||||
static int kallsyms__delta(struct map *map, const char *filename, u64 *delta)
|
||||
static int kallsyms__delta(struct kmap *kmap, const char *filename, u64 *delta)
|
||||
{
|
||||
struct kmap *kmap = map__kmap(map);
|
||||
u64 addr;
|
||||
|
||||
if (!kmap)
|
||||
return -1;
|
||||
|
||||
if (!kmap->ref_reloc_sym || !kmap->ref_reloc_sym->name)
|
||||
return 0;
|
||||
|
||||
@ -1310,19 +1283,23 @@ static int kallsyms__delta(struct map *map, const char *filename, u64 *delta)
|
||||
int __dso__load_kallsyms(struct dso *dso, const char *filename,
|
||||
struct map *map, bool no_kcore)
|
||||
{
|
||||
struct kmap *kmap = map__kmap(map);
|
||||
u64 delta = 0;
|
||||
|
||||
if (symbol__restricted_filename(filename, "/proc/kallsyms"))
|
||||
return -1;
|
||||
|
||||
if (dso__load_all_kallsyms(dso, filename, map) < 0)
|
||||
if (!kmap || !kmap->kmaps)
|
||||
return -1;
|
||||
|
||||
if (kallsyms__delta(map, filename, &delta))
|
||||
if (dso__load_all_kallsyms(dso, filename) < 0)
|
||||
return -1;
|
||||
|
||||
symbols__fixup_end(&dso->symbols[map->type]);
|
||||
symbols__fixup_duplicate(&dso->symbols[map->type]);
|
||||
if (kallsyms__delta(kmap, filename, &delta))
|
||||
return -1;
|
||||
|
||||
symbols__fixup_end(&dso->symbols);
|
||||
symbols__fixup_duplicate(&dso->symbols);
|
||||
|
||||
if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
|
||||
dso->symtab_type = DSO_BINARY_TYPE__GUEST_KALLSYMS;
|
||||
@ -1330,9 +1307,9 @@ int __dso__load_kallsyms(struct dso *dso, const char *filename,
|
||||
dso->symtab_type = DSO_BINARY_TYPE__KALLSYMS;
|
||||
|
||||
if (!no_kcore && !dso__load_kcore(dso, map, filename))
|
||||
return dso__split_kallsyms_for_kcore(dso, map);
|
||||
return map_groups__split_kallsyms_for_kcore(kmap->kmaps, dso);
|
||||
else
|
||||
return dso__split_kallsyms(dso, map, delta);
|
||||
return map_groups__split_kallsyms(kmap->kmaps, dso, delta, map);
|
||||
}
|
||||
|
||||
int dso__load_kallsyms(struct dso *dso, const char *filename,
|
||||
@ -1341,8 +1318,7 @@ int dso__load_kallsyms(struct dso *dso, const char *filename,
|
||||
return __dso__load_kallsyms(dso, filename, map, false);
|
||||
}
|
||||
|
||||
static int dso__load_perf_map(const char *map_path, struct dso *dso,
|
||||
struct map *map)
|
||||
static int dso__load_perf_map(const char *map_path, struct dso *dso)
|
||||
{
|
||||
char *line = NULL;
|
||||
size_t n;
|
||||
@ -1379,12 +1355,12 @@ static int dso__load_perf_map(const char *map_path, struct dso *dso,
|
||||
if (len + 2 >= line_len)
|
||||
continue;
|
||||
|
||||
sym = symbol__new(start, size, STB_GLOBAL, line + len);
|
||||
sym = symbol__new(start, size, STB_GLOBAL, STT_FUNC, line + len);
|
||||
|
||||
if (sym == NULL)
|
||||
goto out_delete_line;
|
||||
|
||||
symbols__insert(&dso->symbols[map->type], sym);
|
||||
symbols__insert(&dso->symbols, sym);
|
||||
nr_syms++;
|
||||
}
|
||||
|
||||
@ -1509,7 +1485,7 @@ int dso__load(struct dso *dso, struct map *map)
|
||||
pthread_mutex_lock(&dso->lock);
|
||||
|
||||
/* check again under the dso->lock */
|
||||
if (dso__loaded(dso, map->type)) {
|
||||
if (dso__loaded(dso)) {
|
||||
ret = 1;
|
||||
goto out;
|
||||
}
|
||||
@ -1542,7 +1518,7 @@ int dso__load(struct dso *dso, struct map *map)
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = dso__load_perf_map(map_path, dso, map);
|
||||
ret = dso__load_perf_map(map_path, dso);
|
||||
dso->symtab_type = ret > 0 ? DSO_BINARY_TYPE__JAVA_JIT :
|
||||
DSO_BINARY_TYPE__NOT_FOUND;
|
||||
goto out;
|
||||
@ -1651,7 +1627,7 @@ int dso__load(struct dso *dso, struct map *map)
|
||||
if (ret > 0) {
|
||||
int nr_plt;
|
||||
|
||||
nr_plt = dso__synthesize_plt_symbols(dso, runtime_ss, map);
|
||||
nr_plt = dso__synthesize_plt_symbols(dso, runtime_ss);
|
||||
if (nr_plt > 0)
|
||||
ret += nr_plt;
|
||||
}
|
||||
@ -1663,17 +1639,16 @@ out_free:
|
||||
if (ret < 0 && strstr(dso->name, " (deleted)") != NULL)
|
||||
ret = 0;
|
||||
out:
|
||||
dso__set_loaded(dso, map->type);
|
||||
dso__set_loaded(dso);
|
||||
pthread_mutex_unlock(&dso->lock);
|
||||
nsinfo__mountns_exit(&nsc);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct map *map_groups__find_by_name(struct map_groups *mg,
|
||||
enum map_type type, const char *name)
|
||||
struct map *map_groups__find_by_name(struct map_groups *mg, const char *name)
|
||||
{
|
||||
struct maps *maps = &mg->maps[type];
|
||||
struct maps *maps = &mg->maps;
|
||||
struct map *map;
|
||||
|
||||
down_read(&maps->lock);
|
||||
@ -1720,7 +1695,7 @@ int dso__load_vmlinux(struct dso *dso, struct map *map,
|
||||
else
|
||||
dso->binary_type = DSO_BINARY_TYPE__VMLINUX;
|
||||
dso__set_long_name(dso, vmlinux, vmlinux_allocated);
|
||||
dso__set_loaded(dso, map->type);
|
||||
dso__set_loaded(dso);
|
||||
pr_debug("Using %s for symbols\n", symfs_vmlinux);
|
||||
}
|
||||
|
||||
|
@ -57,7 +57,8 @@ struct symbol {
|
||||
u64 start;
|
||||
u64 end;
|
||||
u16 namelen;
|
||||
u8 binding;
|
||||
u8 type:4;
|
||||
u8 binding:4;
|
||||
u8 idle:1;
|
||||
u8 ignore:1;
|
||||
u8 inlined:1;
|
||||
@ -259,17 +260,16 @@ int __dso__load_kallsyms(struct dso *dso, const char *filename, struct map *map,
|
||||
bool no_kcore);
|
||||
int dso__load_kallsyms(struct dso *dso, const char *filename, struct map *map);
|
||||
|
||||
void dso__insert_symbol(struct dso *dso, enum map_type type,
|
||||
void dso__insert_symbol(struct dso *dso,
|
||||
struct symbol *sym);
|
||||
|
||||
struct symbol *dso__find_symbol(struct dso *dso, enum map_type type,
|
||||
u64 addr);
|
||||
struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,
|
||||
const char *name);
|
||||
struct symbol *dso__find_symbol(struct dso *dso, u64 addr);
|
||||
struct symbol *dso__find_symbol_by_name(struct dso *dso, const char *name);
|
||||
|
||||
struct symbol *symbol__next_by_name(struct symbol *sym);
|
||||
|
||||
struct symbol *dso__first_symbol(struct dso *dso, enum map_type type);
|
||||
struct symbol *dso__last_symbol(struct dso *dso, enum map_type type);
|
||||
struct symbol *dso__first_symbol(struct dso *dso);
|
||||
struct symbol *dso__last_symbol(struct dso *dso);
|
||||
struct symbol *dso__next_symbol(struct symbol *sym);
|
||||
|
||||
enum dso_type dso__type_fd(int fd);
|
||||
@ -288,7 +288,7 @@ void symbol__exit(void);
|
||||
void symbol__elf_init(void);
|
||||
int symbol__annotation_init(void);
|
||||
|
||||
struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name);
|
||||
struct symbol *symbol__new(u64 start, u64 len, u8 binding, u8 type, const char *name);
|
||||
size_t __symbol__fprintf_symname_offs(const struct symbol *sym,
|
||||
const struct addr_location *al,
|
||||
bool unknown_as_addr,
|
||||
@ -300,7 +300,6 @@ size_t __symbol__fprintf_symname(const struct symbol *sym,
|
||||
bool unknown_as_addr, FILE *fp);
|
||||
size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp);
|
||||
size_t symbol__fprintf(struct symbol *sym, FILE *fp);
|
||||
bool symbol_type__is_a(char symbol_type, enum map_type map_type);
|
||||
bool symbol__restricted_filename(const char *filename,
|
||||
const char *restricted_filename);
|
||||
int symbol__config_symfs(const struct option *opt __maybe_unused,
|
||||
@ -308,8 +307,7 @@ int symbol__config_symfs(const struct option *opt __maybe_unused,
|
||||
|
||||
int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss,
|
||||
struct symsrc *runtime_ss, int kmodule);
|
||||
int dso__synthesize_plt_symbols(struct dso *dso, struct symsrc *ss,
|
||||
struct map *map);
|
||||
int dso__synthesize_plt_symbols(struct dso *dso, struct symsrc *ss);
|
||||
|
||||
char *dso__demangle_sym(struct dso *dso, int kmodule, const char *elf_name);
|
||||
|
||||
@ -317,7 +315,7 @@ void __symbols__insert(struct rb_root *symbols, struct symbol *sym, bool kernel)
|
||||
void symbols__insert(struct rb_root *symbols, struct symbol *sym);
|
||||
void symbols__fixup_duplicate(struct rb_root *symbols);
|
||||
void symbols__fixup_end(struct rb_root *symbols);
|
||||
void __map_groups__fixup_end(struct map_groups *mg, enum map_type type);
|
||||
void map_groups__fixup_end(struct map_groups *mg);
|
||||
|
||||
typedef int (*mapfn_t)(u64 start, u64 len, u64 pgoff, void *data);
|
||||
int file__read_maps(int fd, bool exe, mapfn_t mapfn, void *data,
|
||||
|
@ -58,13 +58,13 @@ size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp)
|
||||
}
|
||||
|
||||
size_t dso__fprintf_symbols_by_name(struct dso *dso,
|
||||
enum map_type type, FILE *fp)
|
||||
FILE *fp)
|
||||
{
|
||||
size_t ret = 0;
|
||||
struct rb_node *nd;
|
||||
struct symbol_name_rb_node *pos;
|
||||
|
||||
for (nd = rb_first(&dso->symbol_names[type]); nd; nd = rb_next(nd)) {
|
||||
for (nd = rb_first(&dso->symbol_names); nd; nd = rb_next(nd)) {
|
||||
pos = rb_entry(nd, struct symbol_name_rb_node, rb_node);
|
||||
fprintf(fp, "%s\n", pos->sym.name);
|
||||
}
|
||||
|
@ -302,23 +302,20 @@ int thread__insert_map(struct thread *thread, struct map *map)
|
||||
static int __thread__prepare_access(struct thread *thread)
|
||||
{
|
||||
bool initialized = false;
|
||||
int i, err = 0;
|
||||
int err = 0;
|
||||
struct maps *maps = &thread->mg->maps;
|
||||
struct map *map;
|
||||
|
||||
for (i = 0; i < MAP__NR_TYPES; ++i) {
|
||||
struct maps *maps = &thread->mg->maps[i];
|
||||
struct map *map;
|
||||
down_read(&maps->lock);
|
||||
|
||||
down_read(&maps->lock);
|
||||
|
||||
for (map = maps__first(maps); map; map = map__next(map)) {
|
||||
err = unwind__prepare_access(thread, map, &initialized);
|
||||
if (err || initialized)
|
||||
break;
|
||||
}
|
||||
|
||||
up_read(&maps->lock);
|
||||
for (map = maps__first(maps); map; map = map__next(map)) {
|
||||
err = unwind__prepare_access(thread, map, &initialized);
|
||||
if (err || initialized)
|
||||
break;
|
||||
}
|
||||
|
||||
up_read(&maps->lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -335,8 +332,6 @@ static int thread__prepare_access(struct thread *thread)
|
||||
static int thread__clone_map_groups(struct thread *thread,
|
||||
struct thread *parent)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* This is new thread, we share map groups for process. */
|
||||
if (thread->pid_ == parent->pid_)
|
||||
return thread__prepare_access(thread);
|
||||
@ -348,9 +343,8 @@ static int thread__clone_map_groups(struct thread *thread,
|
||||
}
|
||||
|
||||
/* But this one is new process, copy maps. */
|
||||
for (i = 0; i < MAP__NR_TYPES; ++i)
|
||||
if (map_groups__clone(thread, parent->mg, i) < 0)
|
||||
return -ENOMEM;
|
||||
if (map_groups__clone(thread, parent->mg) < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -371,8 +365,7 @@ int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp)
|
||||
return thread__clone_map_groups(thread, parent);
|
||||
}
|
||||
|
||||
void thread__find_cpumode_addr_location(struct thread *thread,
|
||||
enum map_type type, u64 addr,
|
||||
void thread__find_cpumode_addr_location(struct thread *thread, u64 addr,
|
||||
struct addr_location *al)
|
||||
{
|
||||
size_t i;
|
||||
@ -384,7 +377,7 @@ void thread__find_cpumode_addr_location(struct thread *thread,
|
||||
};
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(cpumodes); i++) {
|
||||
thread__find_addr_location(thread, cpumodes[i], type, addr, al);
|
||||
thread__find_symbol(thread, cpumodes[i], addr, al);
|
||||
if (al->map)
|
||||
break;
|
||||
}
|
||||
|
@ -92,16 +92,13 @@ size_t thread__fprintf(struct thread *thread, FILE *fp);
|
||||
|
||||
struct thread *thread__main_thread(struct machine *machine, struct thread *thread);
|
||||
|
||||
void thread__find_addr_map(struct thread *thread,
|
||||
u8 cpumode, enum map_type type, u64 addr,
|
||||
struct addr_location *al);
|
||||
struct map *thread__find_map(struct thread *thread, u8 cpumode, u64 addr,
|
||||
struct addr_location *al);
|
||||
|
||||
void thread__find_addr_location(struct thread *thread,
|
||||
u8 cpumode, enum map_type type, u64 addr,
|
||||
struct addr_location *al);
|
||||
struct symbol *thread__find_symbol(struct thread *thread, u8 cpumode,
|
||||
u64 addr, struct addr_location *al);
|
||||
|
||||
void thread__find_cpumode_addr_location(struct thread *thread,
|
||||
enum map_type type, u64 addr,
|
||||
void thread__find_cpumode_addr_location(struct thread *thread, u64 addr,
|
||||
struct addr_location *al);
|
||||
|
||||
static inline void *thread__priv(struct thread *thread)
|
||||
|
@ -28,10 +28,11 @@ static int __report_module(struct addr_location *al, u64 ip,
|
||||
{
|
||||
Dwfl_Module *mod;
|
||||
struct dso *dso = NULL;
|
||||
|
||||
thread__find_addr_location(ui->thread,
|
||||
PERF_RECORD_MISC_USER,
|
||||
MAP__FUNCTION, ip, al);
|
||||
/*
|
||||
* Some callers will use al->sym, so we can't just use the
|
||||
* cheaper thread__find_map() here.
|
||||
*/
|
||||
thread__find_symbol(ui->thread, PERF_RECORD_MISC_USER, ip, al);
|
||||
|
||||
if (al->map)
|
||||
dso = al->map->dso;
|
||||
@ -103,19 +104,7 @@ static int access_dso_mem(struct unwind_info *ui, Dwarf_Addr addr,
|
||||
struct addr_location al;
|
||||
ssize_t size;
|
||||
|
||||
thread__find_addr_map(ui->thread, PERF_RECORD_MISC_USER,
|
||||
MAP__FUNCTION, addr, &al);
|
||||
if (!al.map) {
|
||||
/*
|
||||
* We've seen cases (softice) where DWARF unwinder went
|
||||
* through non executable mmaps, which we need to lookup
|
||||
* in MAP__VARIABLE tree.
|
||||
*/
|
||||
thread__find_addr_map(ui->thread, PERF_RECORD_MISC_USER,
|
||||
MAP__VARIABLE, addr, &al);
|
||||
}
|
||||
|
||||
if (!al.map) {
|
||||
if (!thread__find_map(ui->thread, PERF_RECORD_MISC_USER, addr, &al)) {
|
||||
pr_debug("unwind: no map for %lx\n", (unsigned long)addr);
|
||||
return -1;
|
||||
}
|
||||
|
@ -366,19 +366,7 @@ static int read_unwind_spec_debug_frame(struct dso *dso,
|
||||
static struct map *find_map(unw_word_t ip, struct unwind_info *ui)
|
||||
{
|
||||
struct addr_location al;
|
||||
|
||||
thread__find_addr_map(ui->thread, PERF_RECORD_MISC_USER,
|
||||
MAP__FUNCTION, ip, &al);
|
||||
if (!al.map) {
|
||||
/*
|
||||
* We've seen cases (softice) where DWARF unwinder went
|
||||
* through non executable mmaps, which we need to lookup
|
||||
* in MAP__VARIABLE tree.
|
||||
*/
|
||||
thread__find_addr_map(ui->thread, PERF_RECORD_MISC_USER,
|
||||
MAP__VARIABLE, ip, &al);
|
||||
}
|
||||
return al.map;
|
||||
return thread__find_map(ui->thread, PERF_RECORD_MISC_USER, ip, &al);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -586,12 +574,9 @@ static int entry(u64 ip, struct thread *thread,
|
||||
struct unwind_entry e;
|
||||
struct addr_location al;
|
||||
|
||||
thread__find_addr_location(thread, PERF_RECORD_MISC_USER,
|
||||
MAP__FUNCTION, ip, &al);
|
||||
|
||||
e.sym = thread__find_symbol(thread, PERF_RECORD_MISC_USER, ip, &al);
|
||||
e.ip = al.addr;
|
||||
e.map = al.map;
|
||||
e.sym = al.sym;
|
||||
|
||||
pr_debug("unwind: %s:ip = 0x%" PRIx64 " (0x%" PRIx64 ")\n",
|
||||
al.sym ? al.sym->name : "''",
|
||||
|
@ -139,12 +139,10 @@ static enum dso_type machine__thread_dso_type(struct machine *machine,
|
||||
struct thread *thread)
|
||||
{
|
||||
enum dso_type dso_type = DSO__TYPE_UNKNOWN;
|
||||
struct map *map;
|
||||
struct dso *dso;
|
||||
struct map *map = map_groups__first(thread->mg);
|
||||
|
||||
map = map_groups__first(thread->mg, MAP__FUNCTION);
|
||||
for (; map ; map = map_groups__next(map)) {
|
||||
dso = map->dso;
|
||||
struct dso *dso = map->dso;
|
||||
if (!dso || dso->long_name[0] != '/')
|
||||
continue;
|
||||
dso_type = dso__type(dso, machine);
|
||||
|
Loading…
Reference in New Issue
Block a user