On Tue, 03 Sep 2013 13:06:55 +0530, Hemant Kumar wrote:First of all, thanks for the review.
[SNIP]
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.cYou need to add it to Documentation/perf-probe.txt too. In addition if
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", ¶ms.sdt,
+ "Show and probe on the SDT markers"),
the --sdt option is only able to work with libelf, it should be wrapped
into the #ifdef LIBELF_SUPPORT pair.
And I'm not sure that it's a good idea to have two behavior on a single
option (S) - show and probe (add). Maybe it can be separated into two
or the S option can be used as a flag with existing --list and --add
option?
OPT_END()Did you build it with NO_LIBELF=1 ? I guess not. At least you need a
};
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);
+}
dummy list_markers() function which just returns -1 for such case.
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.cHmm.. I think the name needs to be changed more specific like
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)
populate_sdt_note() or something?
+{Ditto. How about get_sdt_markers() or get_sdt_notes()? I can see that
+ 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)
there are places those 'marker' and 'note' are used here and there. If
they indicate same thing it'd better to unify the term.
+{Shouldn't we check the name of note being "stapsdt" as well as version
+ 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);
(type) 3?
Thanks,
Namhyung
+ /* 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 */