mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Ian Rogers <irogers@google.com>
To: Peter Zijlstra <peterz@infradead.org>,
	Ingo Molnar <mingo@redhat.com>,
	 Arnaldo Carvalho de Melo <acme@kernel.org>,
	Namhyung Kim <namhyung@kernel.org>, Jiri Olsa <jolsa@kernel.org>,
	 Ian Rogers <irogers@google.com>,
	Adrian Hunter <adrian.hunter@intel.com>,
	 James Clark <james.clark@linaro.org>,
	linux-perf-users@vger.kernel.org,  linux-kernel@vger.kernel.org,
	Alireza Haghdoost <haghdoost@uber.com>
Subject: [PATCH v1 4/7] perf symbol: Add reference counting and DECLARE_RC_STRUCT(symbol)
Date: Mon, 28 Sep 2026 00:52:34 -0700	[thread overview]
Message-ID: <20260928075237.3055101-5-irogers@google.com> (raw)
In-Reply-To: <20260928075237.3055101-1-irogers@google.com>

Wrap struct symbol with DECLARE_RC_STRUCT(symbol) and add a refcount_t
refcnt field along with symbol__get(), symbol__put(), and symbol__zput()
helpers:

- Return a counted symbol reference acquired under symbols->lock from
  symbol lookup functions (symbols__find(), dso__find_symbol(),
  map__find_symbol(), dso__find_symbol_by_name(),
  map__find_symbol_by_name(), dso__first_symbol(), dso__last_symbol())
  and iteration helpers (symbols__first_by_idx(),
  symbols__next_by_idx(), symbols__for_each_entry()).
- Update util/annotate.c and util/db-export.c to hash and compare the
  underlying RC_STRUCT(symbol) pointer via RC_CHK_ACCESS(sym) and
  RC_CHK_EQUAL() so REFCNT_CHECKING wrapper pointers for the same
  symbol resolve to the same hashmap entry, and hold a symbol reference
  in struct db_export's sym_db_ids hashmap.
- Update struct addr_location, struct map_symbol, struct call_path,
  struct block_info, struct disasm_line, struct annotated_op_loc, struct
  c2c_sym_Key, inline_list, srcline, thread_stack, and hist/sort/unwind
  consumers to acquire and release symbol references and use
  RC_CHK_EQUAL() for pointer identity comparisons.

Assisted-by: Antigravity:gemini-3.1-pro
Signed-off-by: Ian Rogers <irogers@google.com>
---
 tools/perf/builtin-kallsyms.c                 |   2 +
 tools/perf/builtin-lock.c                     |  17 ++-
 tools/perf/builtin-script.c                   |   4 +-
 tools/perf/builtin-top.c                      |   2 +-
 tools/perf/builtin-trace.c                    |   1 +
 tools/perf/tests/dlfilter-test.c              |   8 +-
 tools/perf/tests/hists_cumulate.c             |   4 +-
 tools/perf/tests/hists_filter.c               |  10 +-
 tools/perf/tests/hists_link.c                 |  16 ++-
 tools/perf/tests/hists_output.c               |   7 +-
 tools/perf/tests/kallsyms-split.c             |   5 +-
 tools/perf/tests/pe-file-parsing.c            |   1 +
 tools/perf/tests/vmlinux-kallsyms.c           |  12 +-
 tools/perf/ui/browsers/hists.c                |   7 +-
 tools/perf/ui/browsers/map.c                  |   7 +-
 tools/perf/ui/stdio/hist.c                    |   3 +-
 tools/perf/util/addr_location.c               |   4 +
 .../perf/util/annotate-arch/annotate-alpha.c  |   2 +-
 .../util/annotate-arch/annotate-loongarch.c   |   4 +-
 tools/perf/util/annotate-arch/annotate-s390.c |   2 +-
 tools/perf/util/annotate.c                    |  22 ++-
 tools/perf/util/block-info.c                  |   6 +-
 tools/perf/util/bpf_lock_contention.c         |  27 +++-
 tools/perf/util/c2c-function.c                |  13 +-
 tools/perf/util/call-path.c                   |  15 +-
 tools/perf/util/callchain.c                   |   4 +-
 tools/perf/util/capstone.c                    |   1 +
 tools/perf/util/db-export.c                   |  35 ++++-
 tools/perf/util/disasm.c                      |  12 +-
 tools/perf/util/event.c                       |   8 +-
 tools/perf/util/hist.c                        |  13 +-
 tools/perf/util/libdw.c                       |   5 +-
 tools/perf/util/lock-contention.c             |   8 +-
 tools/perf/util/machine.c                     |  48 +++++--
 tools/perf/util/map.h                         |  10 +-
 tools/perf/util/map_symbol.c                  |   4 +-
 tools/perf/util/maps.c                        |   3 +-
 tools/perf/util/probe-event.c                 |  17 ++-
 tools/perf/util/python.c                      |  12 +-
 tools/perf/util/sort.c                        |   2 +-
 tools/perf/util/srcline.c                     |   6 +-
 tools/perf/util/symbol-elf.c                  |   6 +-
 tools/perf/util/symbol.c                      | 129 +++++++++++-------
 tools/perf/util/symbol.h                      |  60 +++++---
 tools/perf/util/thread-stack.c                |  12 +-
 tools/perf/util/threads.c                     |  17 ++-
 tools/perf/util/unwind-libdw.c                |   2 +-
 tools/perf/util/unwind-libunwind.c            |   2 +-
 48 files changed, 427 insertions(+), 190 deletions(-)

diff --git a/tools/perf/builtin-kallsyms.c b/tools/perf/builtin-kallsyms.c
index eb62bb4ea602..5b1b87cd54d4 100644
--- a/tools/perf/builtin-kallsyms.c
+++ b/tools/perf/builtin-kallsyms.c
@@ -53,6 +53,8 @@ static int __cmd_kallsyms(int argc, const char **argv)
 			map__unmap_ip(map, symbol__start(symbol)),
 			map__unmap_ip(map, symbol__end(symbol)),
 			symbol__start(symbol), symbol__end(symbol));
+		symbol__put(symbol);
+		map__put(map);
 	}
 out:
 	machine__delete(machine);
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c
index cd060c984068..9b495703cf0c 100644
--- a/tools/perf/builtin-lock.c
+++ b/tools/perf/builtin-lock.c
@@ -1003,12 +1003,16 @@ static int report_lock_contention_begin_event(struct perf_sample *sample)
 					(filters.nr_addrs + 1) * sizeof(*addrs));
 			if (addrs == NULL) {
 				pr_warning("memory allocation failure\n");
+				symbol__put(sym);
+				map__put(kmap);
 				return -ENOMEM;
 			}
 
 			addrs[filters.nr_addrs++] = map__unmap_ip(kmap,
 								  symbol__start(sym));
 			filters.addrs = addrs;
+			symbol__put(sym);
+			map__put(kmap);
 		}
 	}
 
@@ -1019,9 +1023,12 @@ static int report_lock_contention_begin_event(struct perf_sample *sample)
 
 		switch (aggr_mode) {
 		case LOCK_AGGR_ADDR:
-			sym = machine__find_kernel_symbol(machine, key, &kmap);
-			if (sym)
-				name = symbol__name(sym);
+			sym = machine__find_kernel_symbol(machine, key, NULL);
+			if (sym) {
+				scnprintf(buf, sizeof(buf), "%s", symbol__name(sym));
+				name = buf;
+				symbol__put(sym);
+			}
 			break;
 		case LOCK_AGGR_CALLER:
 			name = buf;
@@ -1668,6 +1675,8 @@ static void print_lock_stat_stdio(struct lock_contention *con, struct lock_stat
 			ip = st->callstack[i];
 			sym = machine__find_kernel_symbol(con->machine, ip, &kmap);
 			get_symbol_name_offset(kmap, sym, ip, buf, sizeof(buf));
+			symbol__put(sym);
+			map__put(kmap);
 			fprintf(lock_output, "\t\t\t%#lx  %s\n", (unsigned long)ip, buf);
 		}
 	}
@@ -1721,6 +1730,8 @@ static void print_lock_stat_csv(struct lock_contention *con, struct lock_stat *s
 			ip = st->callstack[i];
 			sym = machine__find_kernel_symbol(con->machine, ip, &kmap);
 			get_symbol_name_offset(kmap, sym, ip, buf, sizeof(buf));
+			symbol__put(sym);
+			map__put(kmap);
 			fprintf(lock_output, "%s %#lx %s", i ? ":" : sep, (unsigned long) ip, buf);
 		}
 		fprintf(lock_output, "\n");
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index f1257a78d975..4b6157fa87b9 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -1426,7 +1426,8 @@ static int ip__fprintf_sym(uint64_t addr, struct thread *thread,
 	if (PRINT_FIELD(SRCLINE))
 		printed += map__fprintf_srcline(al.map, al.addr, "\t", fp);
 	printed += fprintf(fp, "\n");
-	*lastsym = al.sym;
+	symbol__put(*lastsym);
+	*lastsym = symbol__get(al.sym);
 
 	ret = printed;
 out:
@@ -1593,6 +1594,7 @@ static int perf_sample__fprintf_brstackinsn(struct perf_sample *sample,
 			print_srccode(thread, x.cpumode, start + off);
 	}
 out:
+	symbol__put(lastsym);
 	return printed;
 }
 
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 19a21348823c..dd1e475bb4dd 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -211,7 +211,7 @@ static void perf_top__record_precise_ip(struct perf_top *top,
 
 	if (sym == NULL || (use_browser == 0 &&
 			    (top->sym_filter_entry == NULL ||
-			     top->sym_filter_entry->ms.sym != sym)))
+			     !RC_CHK_EQUAL(top->sym_filter_entry->ms.sym, sym))))
 		return;
 
 	notes = symbol__annotation(sym);
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index aaa090912409..ab970fd45e26 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -778,6 +778,7 @@ size_t syscall_arg__scnprintf_ksym(char *bf, size_t size, struct syscall_arg *ar
 			else
 				printed = scnprintf(bf, size, "%s+0x%" PRIx64,
 						    symbol__name(sym), offset);
+			symbol__put(sym);
 			map__put(map);
 			return printed;
 		}
diff --git a/tools/perf/tests/dlfilter-test.c b/tools/perf/tests/dlfilter-test.c
index b4649c79c309..1b7f400761bf 100644
--- a/tools/perf/tests/dlfilter-test.c
+++ b/tools/perf/tests/dlfilter-test.c
@@ -273,12 +273,16 @@ static int get_ip_addr(struct test_data *td)
 		return -1;
 
 	sym = map__find_symbol_by_name(map, "foo");
-	if (sym)
+	if (sym) {
 		td->foo = symbol__start(sym);
+		symbol__put(sym);
+	}
 
 	sym = map__find_symbol_by_name(map, "bar");
-	if (sym)
+	if (sym) {
 		td->bar = symbol__start(sym);
+		symbol__put(sym);
+	}
 
 	map__put(map);
 
diff --git a/tools/perf/tests/hists_cumulate.c b/tools/perf/tests/hists_cumulate.c
index 95b9a629e59e..16637f1e1e23 100644
--- a/tools/perf/tests/hists_cumulate.c
+++ b/tools/perf/tests/hists_cumulate.c
@@ -114,7 +114,8 @@ static int add_hist_entries(struct hists *hists, struct machine *machine)
 		fake_samples[i].thread = thread__get(al.thread);
 		map__put(fake_samples[i].map);
 		fake_samples[i].map = map__get(al.map);
-		fake_samples[i].sym = al.sym;
+		symbol__put(fake_samples[i].sym);
+		fake_samples[i].sym = symbol__get(al.sym);
 	}
 
 	addr_location__exit(&al);
@@ -155,6 +156,7 @@ static void put_fake_samples(void)
 	size_t i;
 
 	for (i = 0; i < ARRAY_SIZE(fake_samples); i++) {
+		symbol__zput(fake_samples[i].sym);
 		map__zput(fake_samples[i].map);
 		thread__zput(fake_samples[i].thread);
 	}
diff --git a/tools/perf/tests/hists_filter.c b/tools/perf/tests/hists_filter.c
index 6c7e4cdc71a7..3bd0b0b270f5 100644
--- a/tools/perf/tests/hists_filter.c
+++ b/tools/perf/tests/hists_filter.c
@@ -93,7 +93,8 @@ static int add_hist_entries(struct evlist *evlist,
 			fake_samples[i].thread = thread__get(al.thread);
 			map__put(fake_samples[i].map);
 			fake_samples[i].map = map__get(al.map);
-			fake_samples[i].sym = al.sym;
+			symbol__put(fake_samples[i].sym);
+			fake_samples[i].sym = symbol__get(al.sym);
 		}
 	}
 	addr_location__exit(&al);
@@ -109,8 +110,11 @@ static void put_fake_samples(void)
 {
 	size_t i;
 
-	for (i = 0; i < ARRAY_SIZE(fake_samples); i++)
-		map__put(fake_samples[i].map);
+	for (i = 0; i < ARRAY_SIZE(fake_samples); i++) {
+		symbol__zput(fake_samples[i].sym);
+		map__zput(fake_samples[i].map);
+		thread__zput(fake_samples[i].thread);
+	}
 }
 
 static int test__hists_filter(struct test_suite *test __maybe_unused, int subtest __maybe_unused)
diff --git a/tools/perf/tests/hists_link.c b/tools/perf/tests/hists_link.c
index cd32c8277627..b91a75a8fa23 100644
--- a/tools/perf/tests/hists_link.c
+++ b/tools/perf/tests/hists_link.c
@@ -99,7 +99,8 @@ static int add_hist_entries(struct evlist *evlist, struct machine *machine)
 			fake_common_samples[k].thread = thread__get(al.thread);
 			map__put(fake_common_samples[k].map);
 			fake_common_samples[k].map = map__get(al.map);
-			fake_common_samples[k].sym = al.sym;
+			symbol__put(fake_common_samples[k].sym);
+			fake_common_samples[k].sym = symbol__get(al.sym);
 		}
 
 		for (k = 0; k < ARRAY_SIZE(fake_samples[i]); k++) {
@@ -119,7 +120,8 @@ static int add_hist_entries(struct evlist *evlist, struct machine *machine)
 			fake_samples[i][k].thread = thread__get(al.thread);
 			map__put(fake_samples[i][k].map);
 			fake_samples[i][k].map = map__get(al.map);
-			fake_samples[i][k].sym = al.sym;
+			symbol__put(fake_samples[i][k].sym);
+			fake_samples[i][k].sym = symbol__get(al.sym);
 		}
 		i++;
 	}
@@ -136,11 +138,15 @@ static void put_fake_samples(void)
 {
 	size_t i, j;
 
-	for (i = 0; i < ARRAY_SIZE(fake_common_samples); i++)
+	for (i = 0; i < ARRAY_SIZE(fake_common_samples); i++) {
 		map__put(fake_common_samples[i].map);
+		symbol__put(fake_common_samples[i].sym);
+	}
 	for (i = 0; i < ARRAY_SIZE(fake_samples); i++) {
-		for (j = 0; j < ARRAY_SIZE(fake_samples[0]); j++)
+		for (j = 0; j < ARRAY_SIZE(fake_samples[0]); j++) {
 			map__put(fake_samples[i][j].map);
+			symbol__put(fake_samples[i][j].sym);
+		}
 	}
 }
 
@@ -150,7 +156,7 @@ static int find_sample(struct sample *samples, size_t nr_samples,
 	while (nr_samples--) {
 		if (RC_CHK_EQUAL(samples->thread, t) &&
 		    RC_CHK_EQUAL(samples->map, m) &&
-		    samples->sym == s)
+		    RC_CHK_EQUAL(samples->sym, s))
 			return 1;
 		samples++;
 	}
diff --git a/tools/perf/tests/hists_output.c b/tools/perf/tests/hists_output.c
index 77fb3a187139..63b9e48ada63 100644
--- a/tools/perf/tests/hists_output.c
+++ b/tools/perf/tests/hists_output.c
@@ -79,7 +79,8 @@ static int add_hist_entries(struct hists *hists, struct machine *machine)
 		fake_samples[i].thread = al.thread;
 		map__put(fake_samples[i].map);
 		fake_samples[i].map = map__get(al.map);
-		fake_samples[i].sym = al.sym;
+		symbol__put(fake_samples[i].sym);
+		fake_samples[i].sym = symbol__get(al.sym);
 	}
 
 	addr_location__exit(&al);
@@ -120,8 +121,8 @@ static void put_fake_samples(void)
 	size_t i;
 
 	for (i = 0; i < ARRAY_SIZE(fake_samples); i++) {
-		map__put(fake_samples[i].map);
-		fake_samples[i].map = NULL;
+		symbol__zput(fake_samples[i].sym);
+		map__zput(fake_samples[i].map);
 	}
 }
 
diff --git a/tools/perf/tests/kallsyms-split.c b/tools/perf/tests/kallsyms-split.c
index 244daa01bd5d..0e5c029a583e 100644
--- a/tools/perf/tests/kallsyms-split.c
+++ b/tools/perf/tests/kallsyms-split.c
@@ -99,6 +99,7 @@ static int test__kallsyms_split(struct test_suite *test __maybe_unused,
 {
 	struct machine m = { 0 };
 	struct map *map = NULL;
+	struct symbol *sym;
 	int ret = TEST_FAIL;
 
 	pr_debug("try to create fake root directory\n");
@@ -139,10 +140,12 @@ static int test__kallsyms_split(struct test_suite *test __maybe_unused,
 		goto out;
 	}
 
-	if (machine__find_kernel_symbol_by_name(&m, "main_symbol3", &map) == NULL) {
+	sym = machine__find_kernel_symbol_by_name(&m, "main_symbol3", &map);
+	if (sym == NULL) {
 		pr_debug("FAIL: failed to find a symbol\n");
 		goto out;
 	}
+	symbol__put(sym);
 
 	if (!RC_CHK_EQUAL(map, machine__kernel_map(&m))) {
 		pr_debug("FAIL: the symbol is not in the kernel map\n");
diff --git a/tools/perf/tests/pe-file-parsing.c b/tools/perf/tests/pe-file-parsing.c
index 30c7da79e109..c9a2f418bdc5 100644
--- a/tools/perf/tests/pe-file-parsing.c
+++ b/tools/perf/tests/pe-file-parsing.c
@@ -64,6 +64,7 @@ static int run_dir(const char *d)
 	dso__sort_by_name(dso);
 	sym = dso__find_symbol_by_name(dso, "main", &idx);
 	TEST_ASSERT_VAL("Failed to find main", sym);
+	symbol__put(sym);
 	dso__delete(dso);
 
 	return TEST_OK;
diff --git a/tools/perf/tests/vmlinux-kallsyms.c b/tools/perf/tests/vmlinux-kallsyms.c
index 98c2a9437ba7..53f7b44af843 100644
--- a/tools/perf/tests/vmlinux-kallsyms.c
+++ b/tools/perf/tests/vmlinux-kallsyms.c
@@ -208,7 +208,7 @@ static int test__vmlinux_matches_kallsyms_sym_cb(struct symbol *sym, void *data)
 	mem_end = map__unmap_ip(args->vmlinux_map, symbol__end(sym));
 
 	first_pair = machine__find_kernel_symbol(&args->kallsyms, mem_start, NULL);
-	pair = first_pair;
+	pair = symbol__get(first_pair);
 
 	if (pair && UM(symbol__start(pair)) == mem_start) {
 next_pair:
@@ -237,8 +237,11 @@ static int test__vmlinux_matches_kallsyms_sym_cb(struct symbol *sym, void *data)
 			 * possible to get proper function end from
 			 * kallsyms.
 			 */
+			symbol__put(pair);
+			symbol__put(first_pair);
 			return 0;
 		} else {
+			symbol__put(pair);
 			pair = machine__find_kernel_symbol_by_name(&args->kallsyms,
 								   symbol__name(sym),
 								   NULL);
@@ -249,15 +252,20 @@ static int test__vmlinux_matches_kallsyms_sym_cb(struct symbol *sym, void *data)
 				pr_debug("WARN: %#" PRIx64 ": diff name v: %s k: %s\n",
 					 mem_start, symbol__name(sym),
 					 symbol__name(pair));
+				symbol__put(pair);
 			} else {
 				pr_debug("WARN: %#" PRIx64 ": diff name v: %s k: %s\n",
 					 mem_start, symbol__name(sym),
 					 symbol__name(first_pair));
 			}
 
+			symbol__put(first_pair);
 			return 0;
 		}
-	} else if (mem_start == map__end(args->kallsyms.vmlinux_map)) {
+	}
+	symbol__put(pair);
+	symbol__put(first_pair);
+	if (mem_start == map__end(args->kallsyms.vmlinux_map)) {
 		/*
 		 * Ignore aliases to _etext, i.e. to the end of the kernel text area,
 		 * such as __indirect_thunk_end.
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index 206657039223..72b071f2604f 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -2522,11 +2522,11 @@ static struct symbol *symbol__new_unresolved(u64 addr, struct map *map)
 	if (sym) {
 		src = symbol__hists(sym, 1);
 		if (!src) {
-			symbol__delete(sym);
+			symbol__put(sym);
 			return NULL;
 		}
 
-		dso__insert_symbol(map__dso(map), sym);
+		dso__insert_symbol(map__dso(map), symbol__get(sym));
 	}
 
 	return sym;
@@ -2812,7 +2812,7 @@ add_script_opt_2(struct popup_action *act, char **optstr,
 	}
 
 	act->ms.thread = thread__get(thread);
-	act->ms.sym = sym;
+	act->ms.sym = symbol__get(sym);
 	act->fn = do_run_script;
 	return 1;
 }
@@ -3201,6 +3201,7 @@ static int evsel__hists_browse(struct evsel *evsel, int nr_events, const char *h
 
 				memset(&hotkey_act, 0, sizeof(hotkey_act));
 				map_symbol__copy(&hotkey_act.ms, &source_ms);
+				symbol__zput(source_ms.sym);
 				do_annotate(browser, &hotkey_act);
 				map_symbol__exit(&hotkey_act.ms);
 			} else {
diff --git a/tools/perf/ui/browsers/map.c b/tools/perf/ui/browsers/map.c
index bb35d4965a3a..2310fbf1ac6d 100644
--- a/tools/perf/ui/browsers/map.c
+++ b/tools/perf/ui/browsers/map.c
@@ -65,12 +65,13 @@ static int map_browser__search(struct map_browser *browser)
 		 * cursor at that entry.
 		 */
 		for (u32 idx = 0; idx < browser->b.nr_entries; ++idx) {
-			if (entries[idx] == sym) {
+			if (RC_CHK_EQUAL(entries[idx], sym)) {
 				browser->b.top = &entries[idx];
 				browser->b.index = browser->b.top_idx = idx;
 				break;
 			}
 		}
+		symbol__put(sym);
 	} else
 		ui_helpline__fpush("%s not found!", target);
 
@@ -136,7 +137,7 @@ int map__browse(struct map *map)
 			for (unsigned int idx = 0; idx < nr_entries; idx++) {
 				struct symbol *pos = symbols->symbols[idx];
 
-				entries[idx] = pos;
+				entries[idx] = symbol__get(pos);
 				if (maxaddr < symbol__end(pos))
 					maxaddr = symbol__end(pos);
 			}
@@ -151,6 +152,8 @@ int map__browse(struct map *map)
 
 	mb.addrlen = snprintf(tmp, sizeof(tmp), "%" PRIx64, maxaddr);
 	ret = map_browser__run(&mb);
+	for (unsigned int idx = 0; idx < nr_entries; idx++)
+		symbol__put(entries[idx]);
 	free(entries);
 	return ret;
 }
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c
index f80cc73909ed..aedc5eb8b1a4 100644
--- a/tools/perf/ui/stdio/hist.c
+++ b/tools/perf/ui/stdio/hist.c
@@ -908,7 +908,8 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
 
 	free(line);
 out:
-	zfree(&rem_sq_bracket);
+	symbol__zput(rem_sq_bracket);
+	rem_hits.ms.sym = NULL;
 
 	return ret;
 }
diff --git a/tools/perf/util/addr_location.c b/tools/perf/util/addr_location.c
index 57e8217a00f9..0f21a01a3843 100644
--- a/tools/perf/util/addr_location.c
+++ b/tools/perf/util/addr_location.c
@@ -2,6 +2,7 @@
 #include "addr_location.h"
 #include "map.h"
 #include "maps.h"
+#include "symbol.h"
 #include "thread.h"
 
 void addr_location__init(struct addr_location *al)
@@ -29,13 +30,16 @@ void addr_location__exit(struct addr_location *al)
 {
 	map__zput(al->map);
 	thread__zput(al->thread);
+	symbol__zput(al->sym);
 }
 
 void addr_location__copy(struct addr_location *dst, struct addr_location *src)
 {
 	thread__put(dst->thread);
 	map__put(dst->map);
+	symbol__put(dst->sym);
 	*dst = *src;
 	dst->thread = thread__get(src->thread);
 	dst->map = map__get(src->map);
+	dst->sym = symbol__get(src->sym);
 }
diff --git a/tools/perf/util/annotate-arch/annotate-alpha.c b/tools/perf/util/annotate-arch/annotate-alpha.c
index ccb13e2338a2..e95f7628a8fe 100644
--- a/tools/perf/util/annotate-arch/annotate-alpha.c
+++ b/tools/perf/util/annotate-arch/annotate-alpha.c
@@ -89,7 +89,7 @@ static int alpha_call__parse(const struct arch *arch, struct ins_operands *ops,
 	if (maps__find_ams(thread__maps(ms->thread), &target) == 0 &&
 	    map__rip_2objdump(target.ms.map,
 			      map__map_ip(target.ms.map, target.addr)) == ops->target.addr)
-		ops->target.sym = target.ms.sym;
+		ops->target.sym = symbol__get(target.ms.sym);
 
 	addr_map_symbol__exit(&target);
 	return 0;
diff --git a/tools/perf/util/annotate-arch/annotate-loongarch.c b/tools/perf/util/annotate-arch/annotate-loongarch.c
index d275730080b7..7fa1739966df 100644
--- a/tools/perf/util/annotate-arch/annotate-loongarch.c
+++ b/tools/perf/util/annotate-arch/annotate-loongarch.c
@@ -57,7 +57,7 @@ static int loongarch_call__parse(const struct arch *arch, struct ins_operands *o
 
 	if (maps__find_ams(thread__maps(ms->thread), &target) == 0 &&
 	    map__rip_2objdump(target.ms.map, map__map_ip(target.ms.map, target.addr)) == ops->target.addr)
-		ops->target.sym = target.ms.sym;
+		ops->target.sym = symbol__get(target.ms.sym);
 
 	addr_map_symbol__exit(&target);
 	return 0;
@@ -101,7 +101,7 @@ static int loongarch_jump__parse(const struct arch *arch, struct ins_operands *o
 
 	if (maps__find_ams(thread__maps(ms->thread), &target) == 0 &&
 	    map__rip_2objdump(target.ms.map, map__map_ip(target.ms.map, target.addr)) == ops->target.addr)
-		ops->target.sym = target.ms.sym;
+		ops->target.sym = symbol__get(target.ms.sym);
 
 	if (!ops->target.outside) {
 		ops->target.offset = target.addr - start;
diff --git a/tools/perf/util/annotate-arch/annotate-s390.c b/tools/perf/util/annotate-arch/annotate-s390.c
index af9cabd0a586..7c8050e04964 100644
--- a/tools/perf/util/annotate-arch/annotate-s390.c
+++ b/tools/perf/util/annotate-arch/annotate-s390.c
@@ -52,7 +52,7 @@ static int s390_call__parse(const struct arch *arch, struct ins_operands *ops,
 
 	if (maps__find_ams(thread__maps(ms->thread), &target) == 0 &&
 	    map__rip_2objdump(target.ms.map, map__map_ip(target.ms.map, target.addr)) == ops->target.addr)
-		ops->target.sym = target.ms.sym;
+		ops->target.sym = symbol__get(target.ms.sym);
 
 	addr_map_symbol__exit(&target);
 	return 0;
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index 9bb7e0ee1b8e..61a5b13c4777 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -194,15 +194,22 @@ static bool sym_ptr_equal(long key1, long key2, void *ctx __maybe_unused)
 struct annotation *symbol__annotation(struct symbol *sym)
 {
 	struct annotation *notes = NULL;
-	long val = 0;
+	long key, val = 0;
 
 	if (!sym)
 		return NULL;
 
+	/*
+	 * Key on the underlying RC_STRUCT(symbol) pointer so all
+	 * REFCNT_CHECKING wrapper pointers for the same symbol map to the
+	 * same annotation entry.
+	 */
+	key = (long)RC_CHK_ACCESS(sym);
+
 	/* Fast path: look up existing annotation under read lock if flagged. */
 	if (symbol__annotated(sym)) {
 		down_read(annotations_lock());
-		if (annotations && hashmap__find(annotations, (long)sym, &val))
+		if (annotations && hashmap__find(annotations, key, &val))
 			notes = (struct annotation *)val;
 		up_read(annotations_lock());
 		if (notes)
@@ -217,7 +224,7 @@ struct annotation *symbol__annotation(struct symbol *sym)
 			up_write(annotations_lock());
 			return &empty_annotation;
 		}
-	} else if (hashmap__find(annotations, (long)sym, &val)) {
+	} else if (hashmap__find(annotations, key, &val)) {
 		notes = (struct annotation *)val;
 		up_write(annotations_lock());
 		return notes;
@@ -229,7 +236,7 @@ struct annotation *symbol__annotation(struct symbol *sym)
 		return &empty_annotation;
 	}
 	annotation__init(notes);
-	if (hashmap__add(annotations, (long)sym, notes) < 0) {
+	if (hashmap__add(annotations, key, notes) < 0) {
 		free(notes);
 		if (hashmap__size(annotations) == 0) {
 			hashmap__free(annotations);
@@ -246,14 +253,15 @@ struct annotation *symbol__annotation(struct symbol *sym)
 void symbol__annotation_delete(struct symbol *sym)
 {
 	struct annotation *notes = NULL;
-	long val = 0;
+	long key, val = 0;
 
 	/* Unannotated symbols avoid taking annotations_lock on teardown. */
 	if (!sym || !symbol__annotated(sym))
 		return;
 
+	key = (long)RC_CHK_ACCESS(sym);
 	down_write(annotations_lock());
-	if (annotations && hashmap__delete(annotations, (long)sym, NULL, &val)) {
+	if (annotations && hashmap__delete(annotations, key, NULL, &val)) {
 		notes = (struct annotation *)val;
 		if (hashmap__size(annotations) == 0) {
 			hashmap__free(annotations);
@@ -567,7 +575,7 @@ int addr_map_symbol__account_cycles(struct addr_map_symbol *ams,
 	 * it starts on the function start.
 	 */
 	if (start &&
-		(start->ms.sym == ams->ms.sym ||
+		(RC_CHK_EQUAL(start->ms.sym, ams->ms.sym) ||
 		 (ams->ms.sym &&
 		  start->addr == symbol__start(ams->ms.sym) + map__start(ams->ms.map))))
 		saddr = start->al_addr;
diff --git a/tools/perf/util/block-info.c b/tools/perf/util/block-info.c
index 5dec6c9dc1a7..6bf13482da80 100644
--- a/tools/perf/util/block-info.c
+++ b/tools/perf/util/block-info.c
@@ -64,8 +64,10 @@ static struct block_info *block_info__new(unsigned int br_cntr_nr)
 
 void block_info__delete(struct block_info *bi)
 {
-	if (bi)
+	if (bi) {
+		symbol__zput(bi->sym);
 		free(bi->br_cntr);
+	}
 	free(bi);
 }
 
@@ -105,7 +107,7 @@ static void init_block_info(struct block_info *bi, struct symbol *sym,
 			    u64 total_cycles, unsigned int br_cntr_nr,
 			    u64 *br_cntr, struct evsel *evsel)
 {
-	bi->sym = sym;
+	bi->sym = symbol__get(sym);
 	bi->start = ch->start;
 	bi->end = offset;
 	bi->cycles = ch->cycles;
diff --git a/tools/perf/util/bpf_lock_contention.c b/tools/perf/util/bpf_lock_contention.c
index 9832c45857d1..bf9b4dc3c3bb 100644
--- a/tools/perf/util/bpf_lock_contention.c
+++ b/tools/perf/util/bpf_lock_contention.c
@@ -145,6 +145,7 @@ static void init_numa_data(struct lock_contention *con)
 	if (sym) {
 		skel->rodata->contig_page_data_addr = map__unmap_ip(kmap,
 								    symbol__start(sym));
+		symbol__put(sym);
 		map__put(kmap);
 		return;
 	}
@@ -161,6 +162,7 @@ static void init_numa_data(struct lock_contention *con)
 		return;
 
 	skel->rodata->node_data_addr = map__unmap_ip(kmap, symbol__start(sym));
+	symbol__put(sym);
 	map__put(kmap);
 
 	/* get the number of online nodes using the last node number + 1 */
@@ -264,12 +266,16 @@ int lock_contention_prepare(struct lock_contention *con)
 					(con->filters->nr_addrs + 1) * sizeof(*addrs));
 			if (addrs == NULL) {
 				pr_warning("memory allocation failure\n");
+				symbol__put(sym);
+				map__put(kmap);
 				continue;
 			}
 
 			addrs[con->filters->nr_addrs++] = map__unmap_ip(kmap,
 									symbol__start(sym));
 			con->filters->addrs = addrs;
+			symbol__put(sym);
+			map__put(kmap);
 		}
 		naddrs = con->filters->nr_addrs ?: has_mmap_lock;
 		skel->rodata->has_addr = 1;
@@ -292,6 +298,8 @@ int lock_contention_prepare(struct lock_contention *con)
 
 			con->delays[i].addr = map__unmap_ip(kmap,
 							    symbol__start(sym));
+			symbol__put(sym);
+			map__put(kmap);
 		}
 		skel->rodata->lock_delay = 1;
 		bpf_map__set_max_entries(skel->maps.lock_delays, con->nr_delays);
@@ -609,9 +617,12 @@ static const char *lock_contention_get_name(struct lock_contention *con,
 			return "siglock";
 
 		/* global locks with symbols */
-		sym = machine__find_kernel_symbol(machine, key->lock_addr_or_cgroup, &kmap);
-		if (sym)
-			return symbol__name(sym);
+		sym = machine__find_kernel_symbol(machine, key->lock_addr_or_cgroup, NULL);
+		if (sym) {
+			snprintf(name_buf, sizeof(name_buf), "%s", symbol__name(sym));
+			symbol__put(sym);
+			return name_buf;
+		}
 
 		/* try semi-global locks collected separately */
 		if (!bpf_map_lookup_elem(lock_fd, &key->lock_addr_or_cgroup, &flags)) {
@@ -658,13 +669,15 @@ static const char *lock_contention_get_name(struct lock_contention *con,
 		offset = map__map_ip(kmap, addr) - symbol__start(sym);
 
 		if (offset == 0)
-			return symbol__name(sym);
-
-		snprintf(name_buf, sizeof(name_buf), "%s+%#lx",
-			 symbol__name(sym), offset);
+			snprintf(name_buf, sizeof(name_buf), "%s", symbol__name(sym));
+		else
+			snprintf(name_buf, sizeof(name_buf), "%s+%#lx",
+				 symbol__name(sym), offset);
+		symbol__put(sym);
 	} else {
 		snprintf(name_buf, sizeof(name_buf), "%#lx", (unsigned long)addr);
 	}
+	map__put(kmap);
 
 	return name_buf;
 }
diff --git a/tools/perf/util/c2c-function.c b/tools/perf/util/c2c-function.c
index 0c50d816653f..5bd7e0364263 100644
--- a/tools/perf/util/c2c-function.c
+++ b/tools/perf/util/c2c-function.c
@@ -976,13 +976,13 @@ c2c_function_hists__level1_entry(struct symbol *sym,
 	/* mem_info__put() will map_symbol__exit() these, so take refs. */
 	mem_info__iaddr(mi)->ms.thread = thread__get(detail_he->ms.thread);
 	mem_info__iaddr(mi)->ms.map = map__get(detail_he->ms.map);
-	mem_info__iaddr(mi)->ms.sym = sym;
+	mem_info__iaddr(mi)->ms.sym = symbol__get(sym);
 	mem_info__daddr(mi)->addr = 0;
 
 	addr_location__init(&al);
 	al.thread = thread__get(synthetic_thread);
 	al.map = map__get(detail_he->ms.map);
-	al.sym = sym;
+	al.sym = symbol__get(sym);
 	al.addr = sym_start;
 	al.level = detail_he->level;
 	al.cpumode = detail_he->cpumode;
@@ -1064,9 +1064,12 @@ c2c_function_hists__level2_entry(struct c2c_hist_entry *level1_c2c,
 		return NULL;
 
 	/* Key this level by the looked-up symbol, not detail_he's. */
-	level2_c2c->he.ms.sym = sym;
-	if (level2_c2c->he.mem_info)
-		mem_info__iaddr(level2_c2c->he.mem_info)->ms.sym = sym;
+	symbol__put(level2_c2c->he.ms.sym);
+	level2_c2c->he.ms.sym = symbol__get(sym);
+	if (level2_c2c->he.mem_info) {
+		symbol__put(mem_info__iaddr(level2_c2c->he.mem_info)->ms.sym);
+		mem_info__iaddr(level2_c2c->he.mem_info)->ms.sym = symbol__get(sym);
+	}
 
 	c2c_child_entry__insert(level1_he, &level2_c2c->he, p, parent, leftmost);
 
diff --git a/tools/perf/util/call-path.c b/tools/perf/util/call-path.c
index 5c60b8be1cf6..5927068fd9b6 100644
--- a/tools/perf/util/call-path.c
+++ b/tools/perf/util/call-path.c
@@ -10,12 +10,13 @@
 #include <stdlib.h>
 
 #include "call-path.h"
+#include "symbol.h"
 
 static void call_path__init(struct call_path *cp, struct call_path *parent,
 			    struct symbol *sym, u64 ip, bool in_kernel)
 {
 	cp->parent = parent;
-	cp->sym = sym;
+	cp->sym = symbol__get(sym);
 	cp->ip = sym ? 0 : ip;
 	cp->db_id = 0;
 	cp->in_kernel = in_kernel;
@@ -38,8 +39,15 @@ struct call_path_root *call_path_root__new(void)
 void call_path_root__free(struct call_path_root *cpr)
 {
 	struct call_path_block *pos, *n;
+	size_t i = 0;
 
+	if (!cpr)
+		return;
+
+	symbol__zput(cpr->call_path.sym);
 	list_for_each_entry_safe(pos, n, &cpr->blocks, node) {
+		for (size_t j = 0; j < CALL_PATH_BLOCK_SIZE && i < cpr->next; j++, i++)
+			symbol__zput(pos->cp[j].sym);
 		list_del_init(&pos->node);
 		free(pos);
 	}
@@ -94,10 +102,11 @@ struct call_path *call_path__findnew(struct call_path_root *cpr,
 		node_parent = *p;
 		cp = rb_entry(node_parent, struct call_path, rb_node);
 
-		if (cp->sym == sym && cp->ip == ip)
+		if (RC_CHK_EQUAL(cp->sym, sym) && cp->ip == ip)
 			return cp;
 
-		if (sym < cp->sym || (sym == cp->sym && ip < cp->ip))
+		if ((sym ? RC_CHK_ACCESS(sym) : NULL) < (cp->sym ? RC_CHK_ACCESS(cp->sym) : NULL) ||
+		    (RC_CHK_EQUAL(sym, cp->sym) && ip < cp->ip))
 			p = &(*p)->rb_left;
 		else
 			p = &(*p)->rb_right;
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index 993b7c744a89..7f4543ea2ab5 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -1094,6 +1094,7 @@ merge_chain_branch(struct callchain_cursor *cursor,
 		struct map_symbol ms = {
 			.thread = thread__get(list->ms.thread),
 			.map = map__get(list->ms.map),
+			.sym = symbol__get(list->ms.sym),
 		};
 		callchain_cursor_append(cursor, list->ip, &ms, false, NULL, 0, 0, 0, list->srcline);
 		list_del_init(&list->list);
@@ -1204,7 +1205,8 @@ int fill_callchain_info(struct addr_location *al, struct callchain_cursor_node *
 
 	map__put(al->map);
 	al->map = map__get(node->ms.map);
-	al->sym = node->ms.sym;
+	symbol__put(al->sym);
+	al->sym = symbol__get(node->ms.sym);
 	al->srcline = node->srcline;
 	al->addr = node->ip;
 
diff --git a/tools/perf/util/capstone.c b/tools/perf/util/capstone.c
index 422a48385b78..69667f41a7fe 100644
--- a/tools/perf/util/capstone.c
+++ b/tools/perf/util/capstone.c
@@ -373,6 +373,7 @@ static void print_capstone_detail(struct cs_insn *insn, char *buf, size_t len,
 			scnprintf(buf, len, "\t# %"PRIx64" <%s+%#"PRIx64">",
 				  orig_addr, symbol__name(sym), sym_offset);
 		}
+		symbol__put(sym);
 		map__put(found_map);
 		break;
 	}
diff --git a/tools/perf/util/db-export.c b/tools/perf/util/db-export.c
index 897cda3fadd2..1029f23be428 100644
--- a/tools/perf/util/db-export.c
+++ b/tools/perf/util/db-export.c
@@ -22,14 +22,24 @@
 #include "db-export.h"
 #include "hashmap.h"
 
+/*
+ * Hash and compare the underlying RC_STRUCT(symbol) pointer so all
+ * REFCNT_CHECKING wrapper pointers for the same symbol resolve to the same
+ * exported database ID.
+ */
 static size_t sym_ptr_hash(long key, void *ctx __maybe_unused)
 {
-	return hash_bits((size_t)key, 16);
+	const struct symbol *sym = (const struct symbol *)key;
+
+	return hash_bits((size_t)RC_CHK_ACCESS(sym), 16);
 }
 
 static bool sym_ptr_equal(long key1, long key2, void *ctx __maybe_unused)
 {
-	return key1 == key2;
+	const struct symbol *sym1 = (const struct symbol *)key1;
+	const struct symbol *sym2 = (const struct symbol *)key2;
+
+	return RC_CHK_EQUAL(sym1, sym2);
 }
 
 int db_export__init(struct db_export *dbe)
@@ -40,8 +50,15 @@ int db_export__init(struct db_export *dbe)
 
 void db_export__exit(struct db_export *dbe)
 {
-	hashmap__free(dbe->sym_db_ids);
-	dbe->sym_db_ids = NULL;
+	if (dbe->sym_db_ids) {
+		struct hashmap_entry *cur;
+		size_t bkt;
+
+		hashmap__for_each_entry(dbe->sym_db_ids, cur, bkt)
+			symbol__put((struct symbol *)cur->pkey);
+		hashmap__free(dbe->sym_db_ids);
+		dbe->sym_db_ids = NULL;
+	}
 	call_return_processor__free(dbe->crp);
 	dbe->crp = NULL;
 }
@@ -187,6 +204,7 @@ int db_export__symbol(struct db_export *dbe, struct symbol *sym,
 		      struct dso *dso)
 {
 	long db_id;
+	struct symbol *sym_key;
 
 	if (db_export__symbol_db_id(dbe, sym))
 		return 0;
@@ -202,8 +220,11 @@ int db_export__symbol(struct db_export *dbe, struct symbol *sym,
 	}
 
 	db_id = ++dbe->symbol_last_db_id;
-	if (hashmap__set(dbe->sym_db_ids, (long)sym, db_id, NULL, NULL))
+	sym_key = symbol__get(sym);
+	if (hashmap__set(dbe->sym_db_ids, (long)sym_key, db_id, NULL, NULL)) {
+		symbol__put(sym_key);
 		return -ENOMEM;
+	}
 
 	if (dbe->export_symbol)
 		return dbe->export_symbol(dbe, sym, dso);
@@ -227,7 +248,7 @@ static int db_ids_from_al(struct db_export *dbe, struct addr_location *al,
 		if (!al->sym) {
 			al->sym = symbol__new(al->addr, 0, 0, 0, "unknown");
 			if (al->sym)
-				dso__insert_symbol(dso, al->sym);
+				dso__insert_symbol(dso, symbol__get(al->sym));
 		}
 
 		if (al->sym) {
@@ -287,7 +308,7 @@ static struct call_path *call_path_from_sample(struct db_export *dbe,
 		 * db_ids_from_al() to perform the export.
 		 */
 		addr_location__init(&al);
-		al.sym = node->ms.sym;
+		al.sym = symbol__get(node->ms.sym);
 		al.map = map__get(node->ms.map);
 		al.addr = node->ip;
 		al.thread = thread__get(thread);
diff --git a/tools/perf/util/disasm.c b/tools/perf/util/disasm.c
index 78b8811dcaa4..cc9865ac6623 100644
--- a/tools/perf/util/disasm.c
+++ b/tools/perf/util/disasm.c
@@ -228,6 +228,7 @@ static void ins_ops__delete(struct ins_operands *ops)
 	zfree(&ops->source.name);
 	zfree(&ops->target.raw);
 	zfree(&ops->target.name);
+	symbol__zput(ops->target.sym);
 }
 
 int ins__raw_scnprintf(const struct ins *ins, char *bf, size_t size,
@@ -290,7 +291,7 @@ static int call__parse(const struct arch *arch, struct ins_operands *ops, struct
 
 	if (maps__find_ams(thread__maps(ms->thread), &target) == 0 &&
 	    map__rip_2objdump(target.ms.map, map__map_ip(target.ms.map, target.addr)) == ops->target.addr)
-		ops->target.sym = target.ms.sym;
+		ops->target.sym = symbol__get(target.ms.sym);
 
 	addr_map_symbol__exit(&target);
 	return 0;
@@ -425,7 +426,7 @@ static int jump__parse(const struct arch *arch, struct ins_operands *ops, struct
 	 */
 	if (maps__find_ams(thread__maps(ms->thread), &target) == 0 &&
 	    map__rip_2objdump(target.ms.map, map__map_ip(target.ms.map, target.addr)) == ops->target.addr)
-		ops->target.sym = target.ms.sym;
+		ops->target.sym = symbol__get(target.ms.sym);
 
 	if (!ops->target.outside) {
 		ops->target.offset = target.addr - start;
@@ -471,12 +472,14 @@ int jump__scnprintf(const struct ins *ins, char *bf, size_t size,
 			 ops->target.offset);
 }
 
-void jump__delete(struct ins_operands *ops __maybe_unused)
+void jump__delete(struct ins_operands *ops)
 {
 	/*
 	 * The ops->jump.raw_comment and ops->jump.raw_func_start belong to the
 	 * raw string, don't free them.
 	 */
+	if (ops)
+		symbol__zput(ops->target.sym);
 }
 
 const struct ins_ops jump_ops = {
@@ -570,6 +573,7 @@ static void lock__delete(struct ins_operands *ops)
 	zfree(&ops->locked.ins.name);
 	zfree(&ops->target.raw);
 	zfree(&ops->target.name);
+	symbol__zput(ops->target.sym);
 }
 
 const struct ins_ops lock_ops = {
@@ -1090,7 +1094,7 @@ static int symbol__parse_objdump_line(struct symbol *sym,
 
 		if (!maps__find_ams(thread__maps(args->ms->thread), &target) &&
 		    symbol__start(target.ms.sym) == target.al_addr)
-			dl->ops.target.sym = target.ms.sym;
+			dl->ops.target.sym = symbol__get(target.ms.sym);
 
 		addr_map_symbol__exit(&target);
 	}
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 939307796a88..a71267af4f3c 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -770,7 +770,7 @@ struct map *thread__find_map_fb(struct thread *thread, u8 cpumode, u64 addr,
 struct symbol *thread__find_symbol(struct thread *thread, u8 cpumode,
 				   u64 addr, struct addr_location *al)
 {
-	al->sym = NULL;
+	symbol__zput(al->sym);
 	if (thread__find_map(thread, cpumode, addr, al))
 		al->sym = map__find_symbol(al->map, al->addr);
 	return al->sym;
@@ -779,7 +779,7 @@ struct symbol *thread__find_symbol(struct thread *thread, u8 cpumode,
 struct symbol *thread__find_symbol_fb(struct thread *thread, u8 cpumode,
 				      u64 addr, struct addr_location *al)
 {
-	al->sym = NULL;
+	symbol__zput(al->sym);
 	if (thread__find_map_fb(thread, cpumode, addr, al))
 		al->sym = map__find_symbol(al->map, al->addr);
 	return al->sym;
@@ -829,7 +829,7 @@ int machine__resolve(struct machine *machine, struct addr_location *al,
 	thread__put(thread);
 	thread = NULL;
 
-	al->sym = NULL;
+	symbol__zput(al->sym);
 	al->cpu = sample->cpu;
 	al->socket = -1;
 	al->srcline = NULL;
@@ -937,7 +937,7 @@ void thread__resolve(struct thread *thread, struct addr_location *al,
 	thread__find_map_fb(thread, sample->cpumode, sample->addr, al);
 
 	al->cpu = sample->cpu;
-	al->sym = NULL;
+	symbol__zput(al->sym);
 
 	if (al->map)
 		al->sym = map__find_symbol(al->map, al->addr);
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index dd388169c25b..7ae4e7664ba7 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -542,6 +542,7 @@ static int hist_entry__init(struct hist_entry *he,
 
 	he->ms.thread = thread__get(he->ms.thread);
 	he->ms.map = map__get(he->ms.map);
+	he->ms.sym = symbol__get(he->ms.sym);
 
 	if (he->branch_info) {
 		/*
@@ -558,8 +559,10 @@ static int hist_entry__init(struct hist_entry *he,
 
 		he->branch_info->from.ms.thread = thread__get(he->branch_info->from.ms.thread);
 		he->branch_info->from.ms.map = map__get(he->branch_info->from.ms.map);
+		he->branch_info->from.ms.sym = symbol__get(he->branch_info->from.ms.sym);
 		he->branch_info->to.ms.thread = thread__get(he->branch_info->to.ms.thread);
 		he->branch_info->to.ms.map = map__get(he->branch_info->to.ms.map);
+		he->branch_info->to.ms.sym = symbol__get(he->branch_info->to.ms.sym);
 	}
 
 	if (he->mem_info) {
@@ -592,6 +595,7 @@ static int hist_entry__init(struct hist_entry *he,
 
 	INIT_LIST_HEAD(&he->pairs.node);
 	he->thread = thread__get(he->thread);
+	he->parent = symbol__get(he->parent);
 	he->hroot_in  = RB_ROOT_CACHED;
 	he->hroot_out = RB_ROOT_CACHED;
 
@@ -727,6 +731,8 @@ static struct hist_entry *hists__findnew_entry(struct hists *hists,
 			if (hists__has(hists, sym) && he->ms.map != entry->ms.map) {
 				if (he->ms.sym) {
 					u64 addr = symbol__start(he->ms.sym);
+
+					symbol__put(he->ms.sym);
 					he->ms.sym = map__find_symbol(entry->ms.map, addr);
 				}
 
@@ -1028,7 +1034,8 @@ iter_next_branch_entry(struct hist_entry_iter *iter, struct addr_location *al)
 	al->thread = thread__get(bi[i].to.ms.thread);
 	map__put(al->map);
 	al->map = map__get(bi[i].to.ms.map);
-	al->sym = bi[i].to.ms.sym;
+	symbol__put(al->sym);
+	al->sym = symbol__get(bi[i].to.ms.sym);
 	al->addr = bi[i].to.addr;
 	return 1;
 }
@@ -1342,9 +1349,11 @@ int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al,
 	if (al)
 		alm = map__get(al->map);
 
+	iter->parent = NULL;
 	err = sample__resolve_callchain(iter->sample, get_tls_callchain_cursor(), &iter->parent,
 					al, max_stack_depth);
 	if (err) {
+		symbol__zput(iter->parent);
 		map__put(alm);
 		return err;
 	}
@@ -1380,6 +1389,7 @@ int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al,
 	if (!err)
 		err = err2;
 
+	symbol__zput(iter->parent);
 	map__put(alm);
 
 	return err;
@@ -1466,6 +1476,7 @@ void hist_entry__delete(struct hist_entry *he)
 	}
 
 	thread__zput(he->thread);
+	symbol__zput(he->parent);
 	map_symbol__exit(&he->ms);
 
 	if (he->branch_info) {
diff --git a/tools/perf/util/libdw.c b/tools/perf/util/libdw.c
index c4504cceb313..ca66c9afdcd6 100644
--- a/tools/perf/util/libdw.c
+++ b/tools/perf/util/libdw.c
@@ -98,7 +98,7 @@ static int libdw_a2l_cb(Dwarf_Die *die, void *_args)
 		 * while DWARF keeps the pre-clone linkage name, which
 		 * left the outer frame spuriously tagged "(inlined)".
 		 */
-		inline_sym = args->sym;
+		inline_sym = symbol__get(args->sym);
 	} else {
 		/*
 		 * Prefer DW_AT_linkage_name so C++ inline frames keep
@@ -156,8 +156,7 @@ static int libdw_a2l_cb(Dwarf_Die *die, void *_args)
 	return 0;
 
 abort_delete_sym:
-	if (symbol__inlined(inline_sym))
-		symbol__delete(inline_sym);
+	symbol__put(inline_sym);
 abort_enomem:
 	args->err = -ENOMEM;
 	return DWARF_CB_ABORT;
diff --git a/tools/perf/util/lock-contention.c b/tools/perf/util/lock-contention.c
index 8ee1b19a8292..367666028eb2 100644
--- a/tools/perf/util/lock-contention.c
+++ b/tools/perf/util/lock-contention.c
@@ -101,7 +101,6 @@ struct lock_stat *lock_stat_findnew(u64 addr, const char *name, int flags)
 
 bool match_callstack_filter(struct machine *machine, u64 *callstack, int max_stack_depth)
 {
-	struct map *kmap;
 	struct symbol *sym;
 	u64 ip;
 	uint16_t e_machine = perf_env__e_machine(machine->env, /*e_flags=*/NULL);
@@ -130,14 +129,17 @@ bool match_callstack_filter(struct machine *machine, u64 *callstack, int max_sta
 			break;
 
 		ip = callstack[i];
-		sym = machine__find_kernel_symbol(machine, ip, &kmap);
+		sym = machine__find_kernel_symbol(machine, ip, NULL);
 		if (sym == NULL)
 			continue;
 
 		list_for_each_entry(filter, &callstack_filters, list) {
-			if (strstr(symbol__name(sym), filter->name))
+			if (strstr(symbol__name(sym), filter->name)) {
+				symbol__put(sym);
 				return true;
+			}
 		}
+		symbol__put(sym);
 	}
 	return false;
 }
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index cb30d858f62d..f1155c608a95 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -824,8 +824,10 @@ static int machine__process_ksymbol_unregister(struct machine *machine,
 		struct dso *dso = map__dso(map);
 
 		sym = dso__find_symbol(dso, map__map_ip(map, map__start(map)));
-		if (sym)
+		if (sym) {
 			dso__delete_symbol(dso, sym);
+			symbol__put(sym);
+		}
 	}
 	map__put(map);
 	return 0;
@@ -2085,7 +2087,7 @@ static void ip__resolve_ams(struct thread *thread,
 	ams->al_addr = al.addr;
 	ams->al_level = al.level;
 	ams->ms.thread = thread__get(al.thread);
-	ams->ms.sym = al.sym;
+	ams->ms.sym = symbol__get(al.sym);
 	ams->ms.map = map__get(al.map);
 	ams->phys_addr = 0;
 	ams->data_page_size = 0;
@@ -2106,7 +2108,7 @@ static void ip__resolve_data(struct thread *thread,
 	ams->al_addr = al.addr;
 	ams->al_level = al.level;
 	ams->ms.thread = thread__get(al.thread);
-	ams->ms.sym = al.sym;
+	ams->ms.sym = symbol__get(al.sym);
 	ams->ms.map = map__get(al.map);
 	ams->phys_addr = phys_addr;
 	ams->data_page_size = daddr_page_size;
@@ -2192,7 +2194,8 @@ static int append_inlines(struct callchain_cursor *cursor, struct map_symbol *ms
 		.map = map__get(map),
 	};
 	list_for_each_entry(ilist, &inline_node->val, list) {
-		ilist_ms.sym = ilist->symbol;
+		symbol__put(ilist_ms.sym);
+		ilist_ms.sym = symbol__get(ilist->symbol);
 		if (first) {
 			ret = callchain_cursor_append(cursor, ip, &ilist_ms,
 						      branch, flags, nr_loop_iter,
@@ -2204,7 +2207,7 @@ static int append_inlines(struct callchain_cursor *cursor, struct map_symbol *ms
 		first = false;
 
 		if (ret != 0)
-			return ret;
+			break;
 	}
 	map_symbol__exit(&ilist_ms);
 
@@ -2270,7 +2273,7 @@ static int add_callchain_ip(struct thread *thread,
 	if (al.sym != NULL) {
 		if (perf_hpp_list.parent && !*parent &&
 		    symbol__match_regex(al.sym, &parent_regex))
-			*parent = al.sym;
+			*parent = symbol__get(al.sym);
 		else if (have_ignore_callees && root_al &&
 		  symbol__match_regex(al.sym, &ignore_callees_regex)) {
 			/* Treat this symbol as the root,
@@ -2290,7 +2293,7 @@ static int add_callchain_ip(struct thread *thread,
 
 	ms.thread = thread__get(al.thread);
 	ms.map = map__get(al.map);
-	ms.sym = al.sym;
+	ms.sym = symbol__get(al.sym);
 
 	if (append_inlines(cursor, &ms, ip, branch, flags, nr_loop_iter,
 			   iter_cycles, branch_from) == 0)
@@ -2451,8 +2454,7 @@ static void save_lbr_cursor_node(struct thread *thread,
 	map_symbol__exit(&lbr_stitch->prev_lbr_cursor[idx].ms);
 	memcpy(&lbr_stitch->prev_lbr_cursor[idx], cursor->curr,
 	       sizeof(struct callchain_cursor_node));
-	lbr_stitch->prev_lbr_cursor[idx].ms.thread = thread__get(cursor->curr->ms.thread);
-	lbr_stitch->prev_lbr_cursor[idx].ms.map = map__get(cursor->curr->ms.map);
+	map_symbol__copy(&lbr_stitch->prev_lbr_cursor[idx].ms, &cursor->curr->ms);
 
 	lbr_stitch->prev_lbr_cursor[idx].valid = true;
 	cursor->pos++;
@@ -2676,9 +2678,7 @@ static bool has_stitched_lbr(struct thread *thread,
 		memcpy(&stitch_node->cursor, &lbr_stitch->prev_lbr_cursor[i],
 		       sizeof(struct callchain_cursor_node));
 
-		stitch_node->cursor.ms.thread =
-			thread__get(lbr_stitch->prev_lbr_cursor[i].ms.thread);
-		stitch_node->cursor.ms.map = map__get(lbr_stitch->prev_lbr_cursor[i].ms.map);
+		map_symbol__copy(&stitch_node->cursor.ms, &lbr_stitch->prev_lbr_cursor[i].ms);
 
 		if (callee)
 			list_add(&stitch_node->node, &lbr_stitch->lists);
@@ -3282,15 +3282,21 @@ struct dso *machine__findnew_dso(struct machine *machine, const char *filename)
 char *machine__resolve_kernel_addr(void *vmachine, unsigned long long *addrp, char **modp)
 {
 	struct machine *machine = vmachine;
-	struct map *map;
+	struct map *map = NULL;
 	struct symbol *sym = machine__find_kernel_symbol(machine, *addrp, &map);
+	char *name;
 
-	if (sym == NULL)
+	if (sym == NULL) {
+		map__put(map);
 		return NULL;
+	}
 
 	*modp = __map__is_kmodule(map) ? (char *)dso__short_name(map__dso(map)) : NULL;
 	*addrp = map__unmap_ip(map, symbol__start(sym));
-	return (char *)symbol__name(sym);
+	name = (char *)symbol__name(sym);
+	symbol__put(sym);
+	map__put(map);
+	return name;
 }
 
 struct machine__for_each_dso_cb_args {
@@ -3338,19 +3344,27 @@ bool machine__is_lock_function(struct machine *machine, u64 addr)
 
 		machine->sched.text_start = map__unmap_ip(kmap,
 							  symbol__start(sym));
+		symbol__put(sym);
+		map__put(kmap);
 
 		/* should not fail from here */
 		sym = machine__find_kernel_symbol_by_name(machine, "__sched_text_end", &kmap);
 		machine->sched.text_end = map__unmap_ip(kmap,
 							symbol__start(sym));
+		symbol__put(sym);
+		map__put(kmap);
 
 		sym = machine__find_kernel_symbol_by_name(machine, "__lock_text_start", &kmap);
 		machine->lock.text_start = map__unmap_ip(kmap,
 							 symbol__start(sym));
+		symbol__put(sym);
+		map__put(kmap);
 
 		sym = machine__find_kernel_symbol_by_name(machine, "__lock_text_end", &kmap);
 		machine->lock.text_end = map__unmap_ip(kmap,
 						       symbol__start(sym));
+		symbol__put(sym);
+		map__put(kmap);
 
 		sym = machine__find_kernel_symbol_by_name(machine, "__traceiter_contention_begin", &kmap);
 		if (sym) {
@@ -3358,6 +3372,8 @@ bool machine__is_lock_function(struct machine *machine, u64 addr)
 								      symbol__start(sym));
 			machine->traceiter.text_end = map__unmap_ip(kmap,
 								    symbol__end(sym));
+			symbol__put(sym);
+			map__put(kmap);
 		}
 		sym = machine__find_kernel_symbol_by_name(machine, "trace_contention_begin", &kmap);
 		if (sym) {
@@ -3365,6 +3381,8 @@ bool machine__is_lock_function(struct machine *machine, u64 addr)
 								  symbol__start(sym));
 			machine->trace.text_end = map__unmap_ip(kmap,
 								symbol__end(sym));
+			symbol__put(sym);
+			map__put(kmap);
 		}
 	}
 
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index 3d8f72e70d49..745eefa79c7f 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -160,13 +160,15 @@ struct thread;
  * @sym_name: the symbol name
  * @pos: the 'struct symbol *' to use as a loop cursor
  * @idx: the cursor index in the symbol names array
+ * Note: caller must call symbol__put(pos) if breaking out of the loop early.
  */
 #define __map__for_each_symbol_by_name(map, sym_name, pos, idx)		\
 	for (pos = map__find_symbol_by_name_idx(map, sym_name, &idx);	\
-	     pos &&						\
-	     !symbol__match_symbol_name(symbol__name(pos), sym_name,	\
-					SYMBOL_TAG_INCLUDE__DEFAULT_ONLY); \
-	     pos = dso__next_symbol_by_name(map__dso(map), &idx))
+	     pos &&							\
+	     (!symbol__match_symbol_name(symbol__name(pos), sym_name,	\
+					 SYMBOL_TAG_INCLUDE__DEFAULT_ONLY) || \
+	      (symbol__zput(pos), false));				\
+	     symbol__put(pos), pos = dso__next_symbol_by_name(map__dso(map), &idx))
 
 #define map__for_each_symbol_by_name(map, sym_name, pos, idx)	\
 	__map__for_each_symbol_by_name(map, sym_name, (pos), idx)
diff --git a/tools/perf/util/map_symbol.c b/tools/perf/util/map_symbol.c
index 11bc0a7f704c..d1ee4e05564e 100644
--- a/tools/perf/util/map_symbol.c
+++ b/tools/perf/util/map_symbol.c
@@ -2,12 +2,14 @@
 #include "map_symbol.h"
 #include "maps.h"
 #include "map.h"
+#include "symbol.h"
 #include "thread.h"
 
 void map_symbol__exit(struct map_symbol *ms)
 {
 	thread__zput(ms->thread);
 	map__zput(ms->map);
+	symbol__zput(ms->sym);
 }
 
 void addr_map_symbol__exit(struct addr_map_symbol *ams)
@@ -19,7 +21,7 @@ void map_symbol__copy(struct map_symbol *dst, struct map_symbol *src)
 {
 	dst->thread = thread__get(src->thread);
 	dst->map = map__get(src->map);
-	dst->sym = src->sym;
+	dst->sym = symbol__get(src->sym);
 }
 
 void addr_map_symbol__copy(struct addr_map_symbol *dst, struct addr_map_symbol *src)
diff --git a/tools/perf/util/maps.c b/tools/perf/util/maps.c
index f808df2fe77b..a6cbe65cc5ca 100644
--- a/tools/perf/util/maps.c
+++ b/tools/perf/util/maps.c
@@ -788,7 +788,7 @@ struct symbol *maps__find_symbol_by_name(struct maps *maps, const char *name, st
 				*mapp = map__get(map);
 			break;
 		}
-		sym = NULL;
+		symbol__zput(sym);
 	}
 
 	for (unsigned int i = 0; i < nr_maps; i++)
@@ -810,6 +810,7 @@ int maps__find_ams(struct maps *maps, struct addr_map_symbol *ams)
 	}
 
 	ams->al_addr = map__map_ip(ams->ms.map, ams->addr);
+	symbol__put(ams->ms.sym);
 	ams->ms.sym = map__find_symbol(ams->ms.map, ams->al_addr);
 
 	return ams->ms.sym ? 0 : -1;
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 47dbe865c2f9..4b2d4db364b8 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -152,6 +152,8 @@ static int kernel_get_symbol_address_by_name(const char *name, u64 *addr,
 		*addr = map__unmap_ip(map, symbol__start(sym)) -
 			((reloc) ? 0 : map__reloc(map)) -
 			((reladdr) ? map__start(map) : 0);
+		symbol__put(sym);
+		map__put(map);
 	}
 	return 0;
 }
@@ -422,6 +424,7 @@ static int find_alternative_probe_point(struct debuginfo *dinfo,
 					   pp->function);
 		} else
 			address = map__unmap_ip(map, symbol__start(sym)) - map__reloc(map);
+		symbol__put(sym);
 		break;
 	}
 	if (!address) {
@@ -728,11 +731,14 @@ static int post_process_probe_trace_point(struct probe_trace_point *tp,
 		else
 			free(tp->symbol);
 		tp->symbol = strdup(symbol__name(sym));
-		if (!tp->symbol)
+		if (!tp->symbol) {
+			symbol__put(sym);
 			return -ENOMEM;
+		}
 	}
 	tp->offset = addr - symbol__start(sym);
 	tp->address -= offs;
+	symbol__put(sym);
 
 	return 0;
 }
@@ -2314,6 +2320,7 @@ static int find_perf_probe_point_from_map(struct probe_trace_point *tp,
 	ret = pp->function ? 0 : -ENOMEM;
 
 out:
+	symbol__put(sym);
 	map__put(map);
 
 	return ret;
@@ -3078,7 +3085,7 @@ static int find_probe_functions_cb(struct symbol *sym, void *data)
 	if (strglobmatch(norm, args->name)) {
 		args->found++;
 		if (args->syms && args->found < probe_conf.max_probes)
-			args->syms[args->found - 1] = sym;
+			args->syms[args->found - 1] = symbol__get(sym);
 	}
 	free(buf);
 	return 0;
@@ -3146,7 +3153,7 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev,
 		goto out;
 	}
 
-	syms = malloc(sizeof(struct symbol *) * probe_conf.max_probes);
+	syms = calloc(probe_conf.max_probes, sizeof(struct symbol *));
 	if (!syms) {
 		ret = -ENOMEM;
 		goto out;
@@ -3291,6 +3298,10 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev,
 	}
 
 out:
+	if (syms) {
+		for (i = 0; i < probe_conf.max_probes; i++)
+			symbol__put(syms[i]);
+	}
 	map__put(map);
 	free(syms);
 	return ret;
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
index d47f6865021e..6c8bce6c795e 100644
--- a/tools/perf/util/python.c
+++ b/tools/perf/util/python.c
@@ -814,7 +814,7 @@ static PyObject *pyrf_sample_event__srccode(PyObject *self, PyObject *args)
 		addr_location__init(&al);
 		al.thread = thread__get(pevent->al.thread);
 		al.map = map__get(pevent->al.map);
-		al.sym = pevent->al.sym;
+		al.sym = symbol__get(pevent->al.sym);
 		al.addr = pevent->al.addr;
 	}
 
@@ -877,6 +877,7 @@ struct pyrf_callchain_node {
 static void pyrf_callchain_node__delete(struct pyrf_callchain_node *pnode)
 {
 	map__put(pnode->map);
+	symbol__put(pnode->sym);
 	Py_TYPE(pnode)->tp_free((PyObject *)pnode);
 }
 
@@ -944,8 +945,10 @@ struct pyrf_callchain {
 static void pyrf_callchain__delete(struct pyrf_callchain *pchain)
 {
 	if (pchain->frames) {
-		for (u64 i = 0; i < pchain->nr_frames; i++)
+		for (u64 i = 0; i < pchain->nr_frames; i++) {
 			map__put(pchain->frames[i].map);
+			symbol__put(pchain->frames[i].sym);
+		}
 		free(pchain->frames);
 	}
 	Py_TYPE(pchain)->tp_free((PyObject *)pchain);
@@ -974,7 +977,7 @@ static PyObject *pyrf_callchain__item(PyObject *obj, Py_ssize_t i)
 
 	pnode->ip = pchain->frames[i].ip;
 	pnode->map = map__get(pchain->frames[i].map);
-	pnode->sym = pchain->frames[i].sym;
+	pnode->sym = symbol__get(pchain->frames[i].sym);
 
 	return (PyObject *)pnode;
 }
@@ -1486,7 +1489,8 @@ static PyObject *pyrf_event__new(const union perf_event *event, struct evsel *ev
 					pchain->frames[i].ip = node->ip;
 					pchain->frames[i].map =
 						map__get(node->ms.map);
-					pchain->frames[i].sym = node->ms.sym;
+					pchain->frames[i].sym =
+						symbol__get(node->ms.sym);
 					callchain_cursor_advance(cursor);
 				}
 				pevent->callchain = (PyObject *)pchain;
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index 89e833f35fd2..79ea71aab13c 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -466,7 +466,7 @@ int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r)
 	if (!sym_l || !sym_r)
 		return cmp_null(sym_l, sym_r);
 
-	if (sym_l == sym_r)
+	if (RC_CHK_EQUAL(sym_l, sym_r))
 		return 0;
 
 	if (symbol__inlined(sym_l) || symbol__inlined(sym_r)) {
diff --git a/tools/perf/util/srcline.c b/tools/perf/util/srcline.c
index 53976de3105c..4151107ccae1 100644
--- a/tools/perf/util/srcline.c
+++ b/tools/perf/util/srcline.c
@@ -118,7 +118,7 @@ struct symbol *new_inline_sym(struct dso *dso,
 
 	if (base_sym && strcmp(funcname, symbol__name(base_sym)) == 0) {
 		/* reuse the real, existing symbol */
-		inline_sym = base_sym;
+		inline_sym = symbol__get(base_sym);
 		/* ensure that we don't alias an inlined symbol, which could
 		 * lead to double frees in inline_node__delete
 		 */
@@ -468,9 +468,7 @@ void inline_node__clear_frames(struct inline_node *node)
 	list_for_each_entry_safe(ilist, tmp, &node->val, list) {
 		list_del_init(&ilist->list);
 		zfree_srcline(&ilist->srcline);
-		/* only the inlined symbols are owned by the list */
-		if (ilist->symbol && symbol__inlined(ilist->symbol))
-			symbol__delete(ilist->symbol);
+		symbol__zput(ilist->symbol);
 		free(ilist);
 	}
 }
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index 73885413073b..90542fb643e9 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -351,10 +351,13 @@ static bool get_ifunc_name(Elf *elf, struct dso *dso, GElf_Ehdr *ehdr,
 
 	/* Expecting the address to be an IFUNC or IFUNC alias */
 	if (!sym || symbol__start(sym) != addr ||
-	    (symbol__type(sym) != STT_GNU_IFUNC && !symbol__ifunc_alias(sym)))
+	    (symbol__type(sym) != STT_GNU_IFUNC && !symbol__ifunc_alias(sym))) {
+		symbol__put(sym);
 		return false;
+	}
 
 	snprintf(buf, buf_sz, "%s@plt", symbol__name(sym));
+	symbol__put(sym);
 
 	return true;
 }
@@ -631,6 +634,7 @@ int dso__synthesize_plt_symbols(struct dso *dso, struct symsrc *ss)
 	f = dso__find_symbol_nocache(dso, shdr_plt.sh_offset);
 	if (f && symbol__start(f) < shdr_plt.sh_offset && symbol__end(f) > shdr_plt.sh_offset)
 		symbol__set_end(f, shdr_plt.sh_offset);
+	symbol__put(f);
 
 	if (!get_plt_sizes(dso, &ehdr, &shdr_plt, &plt_header_size, &plt_entry_size))
 		return 0;
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index d25d8c96ee66..593fccfe3240 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
 #include <dirent.h>
 #include <errno.h>
+#include <stdatomic.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
@@ -228,7 +229,7 @@ void symbols__init(struct symbols *symbols)
 static void symbols__delete_locked(struct symbols *symbols)
 {
 	for (unsigned int i = 0; i < symbols->cnt; i++)
-		symbol__delete(symbols->symbols[i]);
+		symbol__put(symbols->symbols[i]);
 
 	zfree(&symbols->symbols);
 	zfree(&symbols->symbols_by_name);
@@ -331,11 +332,11 @@ void symbols__fixup_duplicate(struct symbols *symbols)
 		if (choose_best_symbol(curr, next) == SYMBOL_A) {
 			if (symbol__type(next) == STT_GNU_IFUNC)
 				symbol__set_ifunc_alias(curr, true);
-			symbol__delete(next);
+			symbol__put(next);
 		} else {
 			if (symbol__type(curr) == STT_GNU_IFUNC)
 				symbol__set_ifunc_alias(next, true);
-			symbol__delete(curr);
+			symbol__put(curr);
 			symbols->symbols[write_idx] = next;
 		}
 	}
@@ -421,81 +422,96 @@ void symbols__fixup_end(struct symbols *symbols, bool is_kallsyms)
 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, sizeof(*sym) + namelen);
-
-	if (sym == NULL)
-		return NULL;
-
-	sym->start   = start;
-	sym->end     = len ? start + len : start;
-	atomic_init(&sym->flags, (type << SYMBOL_FLAG_TYPE_SHIFT) |
-				 (binding << SYMBOL_FLAG_BINDING_SHIFT));
-	sym->namelen = namelen - 1;
-
-	pr_debug4("%s: %s %#" PRIx64 "-%#" PRIx64 "\n",
-		  __func__, name, start, sym->end);
-	memcpy(sym->name, name, namelen);
+	RC_STRUCT(symbol) *sym;
+	struct symbol *res;
+
+	sym = calloc(1, sizeof(*sym) + namelen);
+
+	if (ADD_RC_CHK(res, sym)) {
+		refcount_set(&sym->refcnt, 1);
+		sym->start   = start;
+		sym->end     = len ? start + len : start;
+		atomic_init(&sym->flags, (type << SYMBOL_FLAG_TYPE_SHIFT) |
+					 (binding << SYMBOL_FLAG_BINDING_SHIFT));
+		sym->namelen = namelen - 1;
+
+		pr_debug4("%s: %s %#" PRIx64 "-%#" PRIx64 "\n",
+			  __func__, name, start, sym->end);
+		memcpy(sym->name, name, namelen);
+	} else {
+		free(sym);
+	}
 
-	return sym;
+	return res;
 }
 
 void symbol__delete(struct symbol *sym)
 {
+	if (!sym)
+		return;
 	if (symbol__annotated(sym))
 		symbol__annotation_delete(sym);
-	free(sym);
+	RC_CHK_FREE(sym);
+}
+
+void symbol__put(struct symbol *sym)
+{
+	if (sym && refcount_dec_and_test(symbol__refcnt(sym)))
+		symbol__delete(sym);
+	else
+		RC_CHK_PUT(sym);
 }
 
 void symbol__set_ignore(struct symbol *sym, bool ignore)
 {
 	if (ignore)
-		atomic_fetch_or(&sym->flags, SYMBOL_FLAG_IGNORE);
+		atomic_fetch_or(&RC_CHK_ACCESS(sym)->flags, SYMBOL_FLAG_IGNORE);
 	else
-		atomic_fetch_and(&sym->flags, ~SYMBOL_FLAG_IGNORE);
+		atomic_fetch_and(&RC_CHK_ACCESS(sym)->flags, ~SYMBOL_FLAG_IGNORE);
 }
 
 void symbol__set_annotate2(struct symbol *sym, bool annotate2)
 {
 	if (annotate2)
-		atomic_fetch_or(&sym->flags, SYMBOL_FLAG_ANNOTATE2);
+		atomic_fetch_or(&RC_CHK_ACCESS(sym)->flags, SYMBOL_FLAG_ANNOTATE2);
 	else
-		atomic_fetch_and(&sym->flags, ~SYMBOL_FLAG_ANNOTATE2);
+		atomic_fetch_and(&RC_CHK_ACCESS(sym)->flags, ~SYMBOL_FLAG_ANNOTATE2);
 }
 
 void symbol__set_inlined(struct symbol *sym, bool inlined)
 {
 	if (inlined)
-		atomic_fetch_or(&sym->flags, SYMBOL_FLAG_INLINED);
+		atomic_fetch_or(&RC_CHK_ACCESS(sym)->flags, SYMBOL_FLAG_INLINED);
 	else
-		atomic_fetch_and(&sym->flags, ~SYMBOL_FLAG_INLINED);
+		atomic_fetch_and(&RC_CHK_ACCESS(sym)->flags, ~SYMBOL_FLAG_INLINED);
 }
 
 void symbol__set_ifunc_alias(struct symbol *sym, bool ifunc_alias)
 {
 	if (ifunc_alias)
-		atomic_fetch_or(&sym->flags, SYMBOL_FLAG_IFUNC_ALIAS);
+		atomic_fetch_or(&RC_CHK_ACCESS(sym)->flags, SYMBOL_FLAG_IFUNC_ALIAS);
 	else
-		atomic_fetch_and(&sym->flags, ~SYMBOL_FLAG_IFUNC_ALIAS);
+		atomic_fetch_and(&RC_CHK_ACCESS(sym)->flags, ~SYMBOL_FLAG_IFUNC_ALIAS);
 }
 
 void symbol__set_annotated(struct symbol *sym, bool annotated)
 {
 	if (annotated)
-		atomic_fetch_or(&sym->flags, SYMBOL_FLAG_ANNOTATED);
+		atomic_fetch_or(&RC_CHK_ACCESS(sym)->flags, SYMBOL_FLAG_ANNOTATED);
 	else
-		atomic_fetch_and(&sym->flags, ~SYMBOL_FLAG_ANNOTATED);
+		atomic_fetch_and(&RC_CHK_ACCESS(sym)->flags, ~SYMBOL_FLAG_ANNOTATED);
 }
 
 static void symbol__set_idle(struct symbol *sym, bool idle)
 {
-	uint16_t old_flags = atomic_load_explicit(&sym->flags, memory_order_relaxed);
+	uint16_t old_flags = atomic_load_explicit(&RC_CHK_ACCESS(sym)->flags, memory_order_relaxed);
 	uint16_t new_flags;
 	uint16_t idle_val = idle ? SYMBOL_IDLE__IDLE : SYMBOL_IDLE__NOT_IDLE;
 
 	do {
 		new_flags = old_flags & ~SYMBOL_FLAG_IDLE_MASK;
 		new_flags |= (idle_val << SYMBOL_FLAG_IDLE_SHIFT);
-	} while (!atomic_compare_exchange_weak(&sym->flags, &old_flags, new_flags));
+	} while (!atomic_compare_exchange_weak(&RC_CHK_ACCESS(sym)->flags, &old_flags, new_flags));
 }
 
 int __symbols__insert(struct symbols *symbols, struct symbol *sym)
@@ -506,7 +522,7 @@ int __symbols__insert(struct symbols *symbols, struct symbol *sym)
 					       sizeof(struct symbol *) * to_allocate);
 
 		if (!temp) {
-			symbol__delete(sym);
+			symbol__put(sym);
 			return -ENOMEM;
 		}
 		symbols->symbols = temp;
@@ -559,7 +575,7 @@ static struct symbol *symbols__find(struct symbols *symbols, u64 ip)
 		else if (ip > end || (ip == end && ip != start))
 			low = mid + 1;
 		else {
-			res = s;
+			res = symbol__get(s);
 			break;
 		}
 	}
@@ -684,7 +700,7 @@ static struct symbol *symbols__find_by_name(struct symbol *symbols[],
 		}
 	}
 	assert(!found_idx || !s || s == symbols[*found_idx]);
-	return s;
+	return symbol__get(s);
 }
 
 int dso__insert_symbol(struct dso *dso, struct symbol *sym)
@@ -698,14 +714,16 @@ void dso__delete_symbol(struct dso *dso, struct symbol *sym)
 
 	down_write(&symbols->lock);
 	for (unsigned int i = 0; i < symbols->cnt; i++) {
-		if (symbols->symbols[i] == sym) {
+		if (RC_CHK_EQUAL(symbols->symbols[i], sym)) {
+			struct symbol *old = symbols->symbols[i];
+
 			memmove(&symbols->symbols[i], &symbols->symbols[i + 1],
 				(symbols->cnt - i - 1) * sizeof(struct symbol *));
 			symbols->cnt--;
 			zfree(&symbols->symbols_by_name);
 			symbols->num_by_name = 0;
 			symbols->sorted_by_name = false;
-			symbol__delete(sym);
+			symbol__put(old);
 			break;
 		}
 	}
@@ -724,11 +742,17 @@ struct symbol *dso__find_symbol_nocache(struct dso *dso, u64 addr)
 
 struct symbol *dso__next_symbol_by_name(struct dso *dso, size_t *idx)
 {
-	if (*idx + 1 >= dso__symbol_names_len(dso))
-		return NULL;
+	struct symbols *symbols = dso__symbols(dso);
+	struct symbol *res = NULL;
+
+	down_read(&symbols->lock);
+	if (*idx + 1 < symbols->num_by_name) {
+		++*idx;
+		res = symbol__get(symbols->symbols_by_name[*idx]);
+	}
+	up_read(&symbols->lock);
 
-	++*idx;
-	return dso__symbol_names(dso)[*idx];
+	return res;
 }
 
  /*
@@ -736,16 +760,26 @@ struct symbol *dso__next_symbol_by_name(struct dso *dso, size_t *idx)
   */
 struct symbol *dso__find_symbol_by_name(struct dso *dso, const char *name, size_t *idx)
 {
+	struct symbols *symbols;
 	struct symbol *s;
 
-	dso__sort_by_name(dso);
-	s = symbols__find_by_name(dso__symbol_names(dso),
-				  dso__symbol_names_len(dso),
+	symbols = dso__symbols(dso);
+	down_read(&symbols->lock);
+	while (!symbols->sorted_by_name) {
+		up_read(&symbols->lock);
+		dso__sort_by_name(dso);
+		down_read(&symbols->lock);
+		if (!symbols->sorted_by_name && !symbols->symbols_by_name)
+			break;
+	}
+	s = symbols__find_by_name(symbols->symbols_by_name,
+				  symbols->num_by_name,
 				  name, SYMBOL_TAG_INCLUDE__NONE, idx);
 	if (!s) {
-		s = symbols__find_by_name(dso__symbol_names(dso), dso__symbol_names_len(dso),
+		s = symbols__find_by_name(symbols->symbols_by_name, symbols->num_by_name,
 					  name, SYMBOL_TAG_INCLUDE__DEFAULT_ONLY, idx);
 	}
+	up_read(&symbols->lock);
 	return s;
 }
 
@@ -884,7 +918,8 @@ bool symbol__is_idle(struct symbol *sym, const struct dso *dso, struct perf_env
 	uint16_t e_machine;
 
 	{
-		uint16_t flags = atomic_load_explicit(&sym->flags, memory_order_relaxed);
+		uint16_t flags = atomic_load_explicit(&RC_CHK_ACCESS(sym)->flags,
+						      memory_order_relaxed);
 		uint16_t idle_val = (flags & SYMBOL_FLAG_IDLE_MASK) >> SYMBOL_FLAG_IDLE_SHIFT;
 
 		if (idle_val != SYMBOL_IDLE__UNKNOWN)
@@ -1032,7 +1067,7 @@ static int maps__split_kallsyms_for_kcore(struct maps *kmaps, struct dso *dso)
 		curr_map = maps__find(kmaps, symbol__start(pos));
 
 		if (!curr_map) {
-			symbol__delete(pos);
+			symbol__put(pos);
 			continue;
 		}
 		curr_map_dso = map__dso(curr_map);
@@ -1228,7 +1263,7 @@ static int maps__split_kallsyms(struct maps *kmaps, struct dso *dso, u64 delta,
 
 		continue;
 discard_symbol:
-		symbol__delete(pos);
+		symbol__put(pos);
 	}
 
 	root->cnt = write_idx;
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 52cd6b43696c..a3c88b5224ec 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -13,6 +13,7 @@
 #include <linux/string.h>
 #include <stdio.h>
 #include <errno.h>
+#include <internal/rc_check.h>
 #include "addr_location.h"
 #include "path.h"
 #include "rwsem.h"
@@ -93,10 +94,12 @@ enum symbol_idle_kind {
 /**
  * A symtab entry.
  */
-struct symbol {
+DECLARE_RC_STRUCT(symbol) {
 	/** Range of symbol [start, end). */
 	u64		start;
 	u64		end;
+	/** Reference count. */
+	refcount_t	refcnt;
 	/** Length of the string name. */
 	u16		namelen;
 	_Atomic uint16_t flags;
@@ -143,85 +146,110 @@ void symbols__exit(struct symbols *symbols);
 void symbols__delete(struct symbols *symbols);
 void symbols__sort_read_lock(struct symbols *symbols) SHARED_LOCK_FUNCTION(symbols->lock);
 
+static inline refcount_t *symbol__refcnt(struct symbol *sym)
+{
+	return &RC_CHK_ACCESS(sym)->refcnt;
+}
+
+static inline struct symbol *symbol__get(struct symbol *sym)
+{
+	struct symbol *result;
+
+	if (RC_CHK_GET(result, sym))
+		refcount_inc(symbol__refcnt(sym));
+
+	return result;
+}
+
+void symbol__put(struct symbol *sym);
+
+static inline void __symbol__zput(struct symbol **sym)
+{
+	symbol__put(*sym);
+	*sym = NULL;
+}
+
+#define symbol__zput(sym) __symbol__zput(&sym)
+
 static inline u64 symbol__start(const struct symbol *sym)
 {
-	return sym->start;
+	return RC_CHK_ACCESS(sym)->start;
 }
 
 static inline void symbol__set_start(struct symbol *sym, u64 start)
 {
-	sym->start = start;
+	RC_CHK_ACCESS(sym)->start = start;
 }
 
 static inline u64 symbol__end(const struct symbol *sym)
 {
-	return sym->end;
+	return RC_CHK_ACCESS(sym)->end;
 }
 
 static inline void symbol__set_end(struct symbol *sym, u64 end)
 {
-	sym->end = end;
+	RC_CHK_ACCESS(sym)->end = end;
 }
 
 static inline const char *symbol__name(const struct symbol *sym)
 {
-	return sym->name;
+	return RC_CHK_ACCESS(sym)->name;
 }
 
 static inline u16 symbol__namelen(const struct symbol *sym)
 {
-	return sym->namelen;
+	return RC_CHK_ACCESS(sym)->namelen;
 }
 
 static inline u8 symbol__arch_sym(const struct symbol *sym)
 {
-	return sym->arch_sym;
+	return RC_CHK_ACCESS(sym)->arch_sym;
 }
 
 static inline void symbol__set_arch_sym(struct symbol *sym, u8 arch_sym)
 {
-	sym->arch_sym = arch_sym;
+	RC_CHK_ACCESS(sym)->arch_sym = arch_sym;
 }
 
 static inline u8 symbol__type(const struct symbol *sym)
 {
-	return (atomic_load_explicit(&sym->flags, memory_order_relaxed) &
+	return (atomic_load_explicit(&RC_CHK_ACCESS(sym)->flags, memory_order_relaxed) &
 		SYMBOL_FLAG_TYPE_MASK) >> SYMBOL_FLAG_TYPE_SHIFT;
 }
 
 static inline u8 symbol__binding(const struct symbol *sym)
 {
-	return (atomic_load_explicit(&sym->flags, memory_order_relaxed) &
+	return (atomic_load_explicit(&RC_CHK_ACCESS(sym)->flags, memory_order_relaxed) &
 		SYMBOL_FLAG_BINDING_MASK) >> SYMBOL_FLAG_BINDING_SHIFT;
 }
 
 static inline bool symbol__ignore(const struct symbol *sym)
 {
-	return (atomic_load_explicit(&sym->flags, memory_order_relaxed) &
+	return (atomic_load_explicit(&RC_CHK_ACCESS(sym)->flags, memory_order_relaxed) &
 		SYMBOL_FLAG_IGNORE) != 0;
 }
 
 static inline bool symbol__inlined(const struct symbol *sym)
 {
-	return (atomic_load_explicit(&sym->flags, memory_order_relaxed) &
+	return (atomic_load_explicit(&RC_CHK_ACCESS(sym)->flags, memory_order_relaxed) &
 		SYMBOL_FLAG_INLINED) != 0;
 }
 
 static inline bool symbol__is_annotate2(const struct symbol *sym)
 {
-	return (atomic_load_explicit(&sym->flags, memory_order_relaxed) &
+	return (atomic_load_explicit(&RC_CHK_ACCESS(sym)->flags, memory_order_relaxed) &
 		SYMBOL_FLAG_ANNOTATE2) != 0;
 }
 
 static inline bool symbol__ifunc_alias(const struct symbol *sym)
 {
-	return (atomic_load_explicit(&sym->flags, memory_order_relaxed) &
+	return (atomic_load_explicit(&RC_CHK_ACCESS(sym)->flags, memory_order_relaxed) &
 		SYMBOL_FLAG_IFUNC_ALIAS) != 0;
 }
 
 static inline bool symbol__annotated(const struct symbol *sym)
 {
-	return (atomic_load_explicit(&sym->flags, memory_order_relaxed) &
+	return (atomic_load_explicit(&RC_CHK_ACCESS(sym)->flags, memory_order_relaxed) &
 		SYMBOL_FLAG_ANNOTATED) != 0;
 }
 
diff --git a/tools/perf/util/thread-stack.c b/tools/perf/util/thread-stack.c
index 76867ba83365..e2c73e890158 100644
--- a/tools/perf/util/thread-stack.c
+++ b/tools/perf/util/thread-stack.c
@@ -823,7 +823,7 @@ static int thread_stack__pop_cp(struct thread *thread, struct thread_stack *ts,
 	if (ts->cnt == 1) {
 		struct thread_stack_entry *tse = &ts->stack[0];
 
-		if (tse->cp->sym == sym)
+		if (RC_CHK_EQUAL(tse->cp->sym, sym))
 			return thread_stack__call_return(thread, ts, --ts->cnt,
 							 timestamp, ref, false);
 	}
@@ -941,7 +941,7 @@ static int thread_stack__no_call_return(struct thread *thread,
 	else
 		parent = root;
 
-	if (parent->sym == from_al->sym) {
+	if (RC_CHK_EQUAL(parent->sym, from_al->sym)) {
 		/*
 		 * At the bottom of the stack, assume the missing 'call' was
 		 * before the trace started. So, pop the current symbol and push
@@ -1069,7 +1069,7 @@ static int thread_stack__x86_retpoline(struct thread_stack *ts,
 		 */
 		ts->cnt -= 1;
 		sym = ts->stack[ts->cnt - 2].cp->sym;
-		if (sym && sym == tsym && to_al->addr != symbol__start(tsym)) {
+		if (sym && RC_CHK_EQUAL(sym, tsym) && to_al->addr != symbol__start(tsym)) {
 			/*
 			 * Target is back to the middle of the symbol we came
 			 * from so assume it is an indirect jmp and forget it
@@ -1078,7 +1078,7 @@ static int thread_stack__x86_retpoline(struct thread_stack *ts,
 			ts->cnt -= 1;
 			return 0;
 		}
-	} else if (sym && sym == tsym) {
+	} else if (sym && RC_CHK_EQUAL(sym, tsym)) {
 		/*
 		 * Target is back to the symbol we came from so assume it is an
 		 * indirect jmp and forget it altogether.
@@ -1169,7 +1169,7 @@ int thread_stack__process(struct thread *thread, struct comm *comm,
 		 * may be the start of a x86 retpoline.
 		 */
 		if (!err && rstate == X86_RETPOLINE_POSSIBLE && to_al->sym &&
-		    from_al->sym == to_al->sym &&
+		    RC_CHK_EQUAL(from_al->sym, to_al->sym) &&
 		    to_al->addr != symbol__start(to_al->sym))
 			ts->rstate = X86_RETPOLINE_DETECTED;
 
@@ -1206,7 +1206,7 @@ int thread_stack__process(struct thread *thread, struct comm *comm,
 	} else if (sample->flags & PERF_IP_FLAG_TRACE_END) {
 		err = thread_stack__trace_end(ts, sample, ref);
 	} else if (sample->flags & PERF_IP_FLAG_BRANCH &&
-		   from_al->sym != to_al->sym && to_al->sym &&
+		   !RC_CHK_EQUAL(from_al->sym, to_al->sym) && to_al->sym &&
 		   to_al->addr == symbol__start(to_al->sym)) {
 		struct call_path_root *cpr = ts->crp->cpr;
 		struct call_path *cp;
diff --git a/tools/perf/util/threads.c b/tools/perf/util/threads.c
index 6ca0b178fb6c..b3ec954fe7ab 100644
--- a/tools/perf/util/threads.c
+++ b/tools/perf/util/threads.c
@@ -142,10 +142,13 @@ void threads__remove_all_threads(struct threads *threads)
 		down_write(&table->lock);
 		__threads_table_entry__set_last_match(table, NULL);
 		hashmap__for_each_entry_safe(&table->shard, cur, tmp, bkt) {
-			struct thread *old_value;
+			struct thread *old_value = NULL;
 
-			hashmap__delete(&table->shard, cur->key, /*old_key=*/NULL, &old_value);
-			thread__put(old_value);
+			if (hashmap__delete(&table->shard, cur->key,
+					    /*old_key=*/NULL, &old_value)) {
+				thread__free_stitch_list(old_value);
+				thread__put(old_value);
+			}
 		}
 		up_write(&table->lock);
 	}
@@ -154,14 +157,16 @@ void threads__remove_all_threads(struct threads *threads)
 void threads__remove(struct threads *threads, struct thread *thread)
 {
 	struct threads_table_entry *table  = threads__table(threads, thread__tid(thread));
-	struct thread *old_value;
+	struct thread *old_value = NULL;
 
 	down_write(&table->lock);
 	if (table->last_match && RC_CHK_EQUAL(table->last_match, thread))
 		__threads_table_entry__set_last_match(table, NULL);
 
-	hashmap__delete(&table->shard, thread__tid(thread), /*old_key=*/NULL, &old_value);
-	thread__put(old_value);
+	if (hashmap__delete(&table->shard, thread__tid(thread), /*old_key=*/NULL, &old_value)) {
+		thread__free_stitch_list(old_value);
+		thread__put(old_value);
+	}
 	up_write(&table->lock);
 }
 
diff --git a/tools/perf/util/unwind-libdw.c b/tools/perf/util/unwind-libdw.c
index 87ade098b5c6..eb4327aa9e7e 100644
--- a/tools/perf/util/unwind-libdw.c
+++ b/tools/perf/util/unwind-libdw.c
@@ -169,7 +169,7 @@ static int entry(u64 ip, struct unwind_info *ui)
 	e->ip	  = ip;
 	e->ms.thread = thread__get(al.thread);
 	e->ms.map = map__get(al.map);
-	e->ms.sym = al.sym;
+	e->ms.sym = symbol__get(al.sym);
 
 	pr_debug("unwind: %s:ip = 0x%" PRIx64 " (0x%" PRIx64 ")\n",
 		 al.sym ? symbol__name(al.sym) : "''",
diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c
index 6052383e862b..42872c7b6dcd 100644
--- a/tools/perf/util/unwind-libunwind.c
+++ b/tools/perf/util/unwind-libunwind.c
@@ -632,7 +632,7 @@ static int entry(uint64_t ip, struct thread *thread, unwind_entry_cb_t cb, void
 	e.ms.thread = thread__get(al.thread);
 
 	pr_debug("unwind: %s:ip = 0x%" PRIx64 " (0x%" PRIx64 ")\n",
-		 al.sym ? al.sym->name : "''",
+		 al.sym ? symbol__name(al.sym) : "''",
 		 ip,
 		 al.map ? map__map_ip(al.map, ip) : (u64) 0);
 
-- 
2.56.0.rc1.315.gc6ed9934b7-goog


  parent reply	other threads:[~2026-09-28  7:52 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-28  7:52 [PATCH v1 0/7] perf symbol: Reference counting, flat array storage, and LRU shrinking Ian Rogers
2026-09-28  7:52 ` [PATCH v1 1/7] perf symbol: Add accessor functions for struct symbol fields Ian Rogers
2026-09-28  7:52 ` [PATCH v1 2/7] perf symbol: Remove symbol_conf.priv_size and negative-offset allocations Ian Rogers
2026-09-28  7:52 ` [PATCH v1 3/7] perf symbol: Switch backing storage from rbtree to struct symbols array Ian Rogers
2026-09-28  7:52 ` Ian Rogers [this message]
2026-09-28  7:52 ` [PATCH v1 5/7] perf symbol: Add LRU memory shrinking for symbols, DSOs, and machines Ian Rogers
2026-09-28  7:52 ` [PATCH v1 6/7] perf session: Periodically shrink symbols and DSOs during event processing Ian Rogers
2026-09-28  7:52 ` [PATCH v1 7/7] perf test symbols: Add tests for symbol and DSO LRU shrinking Ian Rogers
2026-09-28 15:37 ` [PATCH v1 0/7] perf symbol: Reference counting, flat array storage, and " Ian Rogers
2026-09-28 19:45 ` Alireza Haghdoost
2026-09-28 20:55   ` Ian Rogers
2026-09-28 21:51     ` Namhyung Kim
2026-09-28 22:04       ` Ian Rogers

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260928075237.3055101-5-irogers@google.com \
    --to=irogers@google.com \
    --cc=acme@kernel.org \
    --cc=adrian.hunter@intel.com \
    --cc=haghdoost@uber.com \
    --cc=james.clark@linaro.org \
    --cc=jolsa@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-perf-users@vger.kernel.org \
    --cc=mingo@redhat.com \
    --cc=namhyung@kernel.org \
    --cc=peterz@infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®