This is the mail archive of the systemtap@sourceware.org mailing list for the systemtap project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH 1/2] SDT markers listing by perf


This patch will enable perf to list all the sdt markers present
in an elf file. The markers are present in the .note.stapsdt section
of the elf. We can traverse through this section and collect the
required info about the markers.
This hasn't been thoroughly tested with the other
options of perf.
----
Usage :
./perf probe --list -x /lib64/libc.so.6

Output :
setjmp
longjmp
longjmp_target
lll_futex_wake
lll_lock_wait_private
longjmp
longjmp_target
lll_futex_wake

Total markers = 8
----
Signed-off-by: Hemant Kumar Shaw <hkshaw@linux.vnet.ibm.com>
---
 tools/perf/builtin-probe.c    |   26 +++++
 tools/perf/util/probe-event.c |    6 +
 tools/perf/util/symbol-elf.c  |  205 +++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/symbol.h      |   19 ++++
 4 files changed, 256 insertions(+)

diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index e8a66f9..3d8dcdf 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -55,6 +55,7 @@ static struct {
 	bool show_funcs;
 	bool mod_events;
 	bool uprobes;
+	bool sdt;
 	int nevents;
 	struct perf_probe_event events[MAX_PROBES];
 	struct strlist *dellist;
@@ -325,6 +326,8 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
 		     opt_set_filter),
 	OPT_CALLBACK('x', "exec", NULL, "executable|path",
 			"target executable name or path", opt_set_target),
+	OPT_BOOLEAN('S', "sdt", &params.sdt,
+		    "Show and probe on the SDT markers"),
 	OPT_END()
 	};
 	int ret;
@@ -355,6 +358,28 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
 	 */
 	symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
 
+	if (params.sdt) {
+		if (params.show_lines) {
+			pr_err("  Error: Don't use --sdt with --line.\n");
+			usage_with_options(probe_usage, options);
+		}
+		if (params.show_vars) {
+			pr_err(" Error: Don't use --sdt with --vars.\n");
+			usage_with_options(probe_usage, options);
+		}
+		if (params.show_funcs) {
+			pr_err("  Error: Don't use --sdt with --funcs.\n");
+			usage_with_options(probe_usage, options);
+		}
+		if (params.list_events) {
+			ret = show_available_markers(params.target);
+			if (ret < 0)
+				pr_err("  Error: Failed to show markers."
+				       " (%d)\n", ret);
+			return ret;
+		}
+	}
+
 	if (params.list_events) {
 		if (params.mod_events) {
 			pr_err("  Error: Don't use --list with --add/--del.\n");
@@ -382,6 +407,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
 			       ret);
 		return ret;
 	}
+
 	if (params.show_funcs) {
 		if (params.nevents != 0 || params.dellist) {
 			pr_err("  Error: Don't use --funcs with"
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index aa04bf9..7f846f9 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -2372,3 +2372,9 @@ out:
 		free(name);
 	return ret;
 }
+
+int show_available_markers(const char *target)
+{
+	setup_pager();
+	return list_markers(target);
+}
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index 4b12bf8..f3630f2 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -846,6 +846,211 @@ out_elf_end:
 	return err;
 }
 
+/* Populate the name, type, offset and argument fields in the note structure */
+static struct sdt_note *populate_note(Elf **elf, const char *data, size_t len,
+				      int type)
+{
+	const char *provider, *name, *args;
+	struct sdt_note *note;
+
+	/*
+	 * There are 3 address values to be obtained: marker offset, base address
+	 * and semaphore
+	 */
+	union {
+		Elf64_Addr a64[3];
+		Elf32_Addr a32[3];
+	} buf;
+
+	/*
+	 * dst and src (of Elf_Data) are required for translation from file
+	 * to memory representation
+	 */
+	Elf_Data dst = {
+		.d_buf = &buf, .d_type = ELF_T_ADDR, .d_version = EV_CURRENT,
+		.d_size = gelf_fsize((*elf), ELF_T_ADDR, 3, EV_CURRENT),
+		.d_off = 0, .d_align = 0
+	};
+
+	Elf_Data src = {
+		.d_buf = (void *) data, .d_type = ELF_T_ADDR,
+		.d_version = EV_CURRENT, .d_size = dst.d_size, .d_off = 0,
+		.d_align = 0
+	};
+
+	if (type != SDT_NOTE_TYPE)
+		goto out_ret;
+
+	note = zalloc(sizeof(struct sdt_note));
+	if (note == NULL) {
+		pr_err("memory allocation error\n");
+		goto out_ret;
+	}
+	note->next = NULL;
+
+	if (len < dst.d_size + 3)
+		goto out_free;
+	/*
+	 * Translating from file representation to memory representation
+	 * Data now points to the address (offset)
+	 */
+	if (gelf_xlatetom((*elf), &dst, &src,
+			  elf_getident((*elf), NULL)[EI_DATA]) == NULL)
+		pr_debug("gelf_xlatetom : %s", elf_errmsg(-1));
+
+	/* Populate the fields of sdt_note */
+	provider = data + dst.d_size;
+
+	name = (const char *)memchr(provider, '\0', data + len - provider);
+	if (name++ == NULL)
+		goto out_ret;
+
+	args = (const char *)memchr(name, '\0', data + len - name);
+	if (args++ == NULL ||
+	    memchr(args, '\0', data + len - name) != data + len - 1)
+		goto out_ret;
+	note->provider = provider;
+	note->name = name;
+
+	/* Three addr's for location, base and semaphore addresses */
+	note->addr.a64[0] = (buf.a64[0]);
+	note->addr.a64[1] = (buf.a64[1]);
+	note->addr.a64[2] = (buf.a64[2]);
+	return note;
+
+out_free:
+	free(note);
+out_ret:
+	return NULL;
+}
+
+/*
+ * Traverse the elf of the object, find out the .note.stapsdt section
+ * and accordingly initialize the notes' list head
+ */
+static struct sdt_note *get_elf_markers(Elf *elf, bool *exe, bool probe)
+{
+	Elf_Scn *scn = NULL;
+	Elf_Data *data;
+	GElf_Shdr shdr;
+	GElf_Ehdr ehdr;
+	size_t  shstrndx;
+	size_t next;
+	GElf_Nhdr nhdr;
+	size_t name_off, desc_off, offset;
+	struct sdt_note *note = NULL, *tmp, *head = NULL;
+
+	if (gelf_getehdr(elf, &ehdr) == NULL) {
+		pr_debug("%s: cannot get elf header.\n", __func__);
+		goto out_end;
+	}
+
+	if (elf_getshdrstrndx(elf, &shstrndx) != 0) {
+		pr_debug("getshdrstrndx failed\n");
+		goto out_end;
+	}
+
+	/* library or exec */
+	if (probe) {
+		if (ehdr.e_type == ET_EXEC)
+			*exe = true;
+	}
+
+	/*
+	 * Look for Section type = SHT_NOTE, flags = no SHF_ALLOC
+	 * and name = .note.stapsdt
+	 */
+	scn = elf_section_by_name(elf, &ehdr, &shdr, NOTE_SCN, NULL);
+	if (scn == NULL) {
+		pr_err("%s section not found!\n", NOTE_SCN);
+		goto out_end;
+	}
+
+	if (!(shdr.sh_type == SHT_NOTE) || (shdr.sh_flags & SHF_ALLOC))
+		goto out_end;
+
+	data = elf_getdata(scn, NULL);
+
+	/* Get the notes */
+	for (offset = 0; (next = gelf_getnote(data, offset, &nhdr, &name_off,
+					      &desc_off)) > 0; offset = next) {
+		tmp = populate_note(&elf, (const char *)((long)(data->d_buf) +
+							 (long)desc_off),
+				    nhdr.n_descsz, nhdr.n_type);
+		/* For first note */
+		if (!head) {
+			note = tmp;
+			head = note;
+			continue;
+		}
+		note->next = tmp;
+		note = note->next;
+	}
+
+	if (!head)
+		pr_err("No markers found\n");
+
+out_end:
+	return head;
+}
+
+static void print_notes(struct sdt_note *start)
+{
+	struct sdt_note *temp;
+	int c;
+
+	for (temp = start, c = 0; temp != NULL; temp = temp->next, c++)
+		printf("%s:%s\n", temp->provider, temp->name);
+
+	printf("\nTotal markers = %d\n", c);
+}
+
+int list_markers(const char *name)
+{
+	int fd, ret = -1;
+	Elf *elf;
+	struct sdt_note *head = NULL;
+
+	fd = open(name, O_RDONLY);
+	if (fd < 0) {
+		pr_err("Failed to open %s\n", name);
+		goto out_ret;
+	}
+
+	symbol__elf_init();
+	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
+	if (elf == NULL) {
+		pr_err("%s: cannot read %s ELF file.\n", __func__, name);
+		goto out_close;
+	}
+
+	head = get_elf_markers(elf, NULL, false);
+	if (head) {
+		print_notes(head);
+		cleanup_notes(head);
+		ret = 0;
+	} else {
+		pr_err("No SDT markers found in %s\n", name);
+	}
+	elf_end(elf);
+
+out_close:
+	close(fd);
+out_ret:
+	return ret;
+}
+
+void cleanup_notes(struct sdt_note *start)
+{
+	struct sdt_note *tmp;
+
+	while (start) {
+		tmp = start->next;
+		free(start);
+		start = tmp;
+	}
+}
+
 void symbol__elf_init(void)
 {
 	elf_version(EV_CURRENT);
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 5f720dc..f2d17b7 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -197,6 +197,17 @@ struct symsrc {
 #endif
 };
 
+/* Note structure */
+struct sdt_note {
+	const char *name;
+	const char *provider;
+	union {
+		Elf64_Addr a64[3];
+		Elf32_Addr a32[3];
+	} addr;
+	struct sdt_note *next;
+};
+
 void symsrc__destroy(struct symsrc *ss);
 int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name,
 		 enum dso_binary_type type);
@@ -247,4 +258,12 @@ 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);
 
+/* For SDT markers */
+int show_available_markers(const char *module);
+int list_markers(const char *name);
+void cleanup_notes(struct sdt_note *start);
+
+#define SDT_NOTE_TYPE 3
+#define NOTE_SCN ".note.stapsdt"
+
 #endif /* __PERF_SYMBOL */


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]