Re: [PATCH v3 1/5] perf/sdt: ELF support for SDT

2014-10-22 Thread Hemant Kumar


On 10/22/2014 08:09 AM, Namhyung Kim wrote:

Hi Hemant,

On Fri, 10 Oct 2014 16:27:53 +0530, Hemant Kumar wrote:

This patch serves the initial support to identify and list SDT events in 
binaries.
When programs containing SDT markers are compiled, gcc with the help of 
assembler
directives identifies them and places them in the section ".note.stapsdt". To 
find
these markers from the binaries, one needs to traverse through this section and
parse the relevant details like the name, type and location of the marker. Also,
the original location could be skewed due to the effect of prelinking. If that 
is
the case, the locations need to be adjusted.

The functions in this patch open a given ELF, find out the SDT section, parse 
the
relevant details, adjust the location (if necessary) and populate them in a 
list.

Signed-off-by: Hemant Kumar 

Acked-by: Namhyung Kim 

Just a nitpick below..



+static int construct_sdt_notes_list(Elf *elf, struct list_head *sdt_notes)
+{
+   GElf_Ehdr ehdr;
+   Elf_Scn *scn = NULL;
+   Elf_Data *data;
+   GElf_Shdr shdr;
+   size_t shstrndx, next;
+   GElf_Nhdr nhdr;
+   size_t name_off, desc_off, offset;
+   int ret = 0;
+
+   if (gelf_getehdr(elf, &ehdr) == NULL) {
+   ret = -EBADF;
+   goto out_ret;
+   }
+   if (elf_getshdrstrndx(elf, &shstrndx) != 0) {
+   ret = -EBADF;
+   goto out_ret;
+   }
+
+   /* Look for the required section */
+   scn = elf_section_by_name(elf, &ehdr, &shdr, SDT_NOTE_SCN, NULL);
+   if (!scn) {
+   ret = -ENOENT;
+   goto out_ret;
+   }
+
+   if (!(shdr.sh_type == SHT_NOTE) || (shdr.sh_flags & SHF_ALLOC)) {

I think the below is more readable:


Yes.



if ((shdr.sh_type != SHT_NOTE) || (shdr.sh_flags & SHF_ALLOC)) {


Will change to this.



Other than that, looks good to me!

Thanks,
Namhyung



+   ret = -ENOENT;
+   goto out_ret;
+   }
+
+   data = elf_getdata(scn, NULL);
+
+   /* Get the SDT notes */
+   for (offset = 0; (next = gelf_getnote(data, offset, &nhdr, &name_off,
+ &desc_off)) > 0; offset = next) {
+   if (nhdr.n_namesz == sizeof(SDT_NOTE_NAME) &&
+   !memcmp(data->d_buf + name_off, SDT_NOTE_NAME,
+   sizeof(SDT_NOTE_NAME))) {
+   ret = populate_sdt_note(&elf, ((data->d_buf) + 
desc_off),
+   nhdr.n_descsz, nhdr.n_type,
+   sdt_notes);
+   if (ret < 0)
+   goto out_ret;
+   }
+   }
+   if (list_empty(sdt_notes))
+   ret = -ENOENT;
+
+out_ret:
+   return ret;
+}


--
Thanks,
Hemant Kumar

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH v3 1/5] perf/sdt: ELF support for SDT

2014-10-21 Thread Namhyung Kim
Hi Hemant,

On Fri, 10 Oct 2014 16:27:53 +0530, Hemant Kumar wrote:
> This patch serves the initial support to identify and list SDT events in 
> binaries.
> When programs containing SDT markers are compiled, gcc with the help of 
> assembler
> directives identifies them and places them in the section ".note.stapsdt". To 
> find
> these markers from the binaries, one needs to traverse through this section 
> and
> parse the relevant details like the name, type and location of the marker. 
> Also,
> the original location could be skewed due to the effect of prelinking. If 
> that is
> the case, the locations need to be adjusted.
>
> The functions in this patch open a given ELF, find out the SDT section, parse 
> the
> relevant details, adjust the location (if necessary) and populate them in a 
> list.
>
> Signed-off-by: Hemant Kumar 

Acked-by: Namhyung Kim 

Just a nitpick below..


> +static int construct_sdt_notes_list(Elf *elf, struct list_head *sdt_notes)
> +{
> + GElf_Ehdr ehdr;
> + Elf_Scn *scn = NULL;
> + Elf_Data *data;
> + GElf_Shdr shdr;
> + size_t shstrndx, next;
> + GElf_Nhdr nhdr;
> + size_t name_off, desc_off, offset;
> + int ret = 0;
> +
> + if (gelf_getehdr(elf, &ehdr) == NULL) {
> + ret = -EBADF;
> + goto out_ret;
> + }
> + if (elf_getshdrstrndx(elf, &shstrndx) != 0) {
> + ret = -EBADF;
> + goto out_ret;
> + }
> +
> + /* Look for the required section */
> + scn = elf_section_by_name(elf, &ehdr, &shdr, SDT_NOTE_SCN, NULL);
> + if (!scn) {
> + ret = -ENOENT;
> + goto out_ret;
> + }
> +
> + if (!(shdr.sh_type == SHT_NOTE) || (shdr.sh_flags & SHF_ALLOC)) {

I think the below is more readable:

if ((shdr.sh_type != SHT_NOTE) || (shdr.sh_flags & SHF_ALLOC)) {

Other than that, looks good to me!

Thanks,
Namhyung


> + ret = -ENOENT;
> + goto out_ret;
> + }
> +
> + data = elf_getdata(scn, NULL);
> +
> + /* Get the SDT notes */
> + for (offset = 0; (next = gelf_getnote(data, offset, &nhdr, &name_off,
> +   &desc_off)) > 0; offset = next) {
> + if (nhdr.n_namesz == sizeof(SDT_NOTE_NAME) &&
> + !memcmp(data->d_buf + name_off, SDT_NOTE_NAME,
> + sizeof(SDT_NOTE_NAME))) {
> + ret = populate_sdt_note(&elf, ((data->d_buf) + 
> desc_off),
> + nhdr.n_descsz, nhdr.n_type,
> + sdt_notes);
> + if (ret < 0)
> + goto out_ret;
> + }
> + }
> + if (list_empty(sdt_notes))
> + ret = -ENOENT;
> +
> +out_ret:
> + return ret;
> +}
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v3 1/5] perf/sdt: ELF support for SDT

2014-10-10 Thread Hemant Kumar
This patch serves the initial support to identify and list SDT events in 
binaries.
When programs containing SDT markers are compiled, gcc with the help of 
assembler
directives identifies them and places them in the section ".note.stapsdt". To 
find
these markers from the binaries, one needs to traverse through this section and
parse the relevant details like the name, type and location of the marker. Also,
the original location could be skewed due to the effect of prelinking. If that 
is
the case, the locations need to be adjusted.

The functions in this patch open a given ELF, find out the SDT section, parse 
the
relevant details, adjust the location (if necessary) and populate them in a 
list.

Signed-off-by: Hemant Kumar 
---
 tools/perf/util/symbol-elf.c |  257 ++
 tools/perf/util/symbol.h |   21 +++
 2 files changed, 278 insertions(+)

diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index 1e23a5b..e403df6 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -1677,6 +1677,263 @@ void kcore_extract__delete(struct kcore_extract *kce)
unlink(kce->extract_filename);
 }
 
+/**
+ * populate_sdt_note : Parse raw data and identify SDT note
+ * @elf: elf of the opened file
+ * @data: raw data of a section with description offset applied
+ * @len: note description size
+ * @type: type of the note
+ * @sdt_notes: List to add the SDT note
+ *
+ * Responsible for parsing the @data in section .note.stapsdt in @elf and
+ * if its an SDT note, it appends to @sdt_notes list.
+ */
+static int populate_sdt_note(Elf **elf, const char *data, size_t len, int type,
+struct list_head *sdt_notes)
+{
+   const char *provider, *name;
+   struct sdt_note *tmp = NULL;
+   GElf_Ehdr ehdr;
+   GElf_Addr base_off = 0;
+   GElf_Shdr shdr;
+   int i, ret = -EINVAL;
+
+   union {
+   Elf64_Addr a64[3];
+   Elf32_Addr a32[3];
+   } buf;
+
+   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
+   };
+
+   /* Check the type of each of the notes */
+   if (type != SDT_NOTE_TYPE)
+   goto out_err;
+
+   tmp = (struct sdt_note *)calloc(1, sizeof(struct sdt_note));
+   if (!tmp) {
+   ret = -ENOMEM;
+   goto out_err;
+   }
+
+   INIT_LIST_HEAD(&tmp->note_list);
+
+   if (len < dst.d_size + 3)
+   goto out_free_note;
+
+   /* Translation from file representation to memory representation */
+   if (gelf_xlatetom(*elf, &dst, &src,
+ elf_getident(*elf, NULL)[EI_DATA]) == NULL) {
+   pr_err("gelf_xlatetom : %s\n", elf_errmsg(-1));
+   goto out_free_note;
+   }
+
+   /* 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_free_note;
+
+   tmp->provider = strdup(provider);
+   if (!tmp->provider) {
+   ret = -ENOMEM;
+   goto out_free_note;
+   }
+   tmp->name = strdup(name);
+   if (!tmp->name) {
+   ret = -ENOMEM;
+   goto out_free_prov;
+   }
+
+   /* Obtain the addresses */
+   if (gelf_getclass(*elf) == ELFCLASS32) {
+   for (i = 0; i < 3; i++)
+   tmp->addr.a32[i] = buf.a32[i];
+   tmp->bit32 = true;
+   } else {
+   for (i = 0; i < 3; i++)
+   tmp->addr.a64[i] = buf.a64[i];
+   tmp->bit32 = false;
+   }
+
+   /* Now Adjust the prelink effect */
+   if (!gelf_getehdr(*elf, &ehdr)) {
+   pr_debug("%s : cannot get elf header.\n", __func__);
+   ret = -EBADF;
+   goto out_free_name;
+   }
+
+   /*
+* Find out the .stapsdt.base section.
+* This scn will help us to handle prelinking (if present).
+* Compare the retrieved file offset of the base section with the
+* base address in the description of the SDT note. If its different,
+* then accordingly, adjust the note location.
+*/
+   if (elf_section_by_name(*elf, &ehdr, &shdr, SDT_BASE_SCN, NULL)) {
+   base_off = shdr.sh_offset;
+   if (base_off) {
+   if (tmp->bit32)
+   tmp->addr.a32[0] = tmp->addr.a32[0] + base_off -
+   tmp->addr.a32[1];
+   else
+