Implement SDT probe description parsing function
authorFrancis Deslauriers <francis.deslauriers@efficios.com>
Wed, 27 Jun 2018 21:26:25 +0000 (17:26 -0400)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Fri, 24 Aug 2018 19:52:47 +0000 (15:52 -0400)
This commit adds the lttng_elf_get_sdt_probe_offsets function to find
the SDT probe matching the received arguments and parses the SDT ELF note
section to return the number of callsite for this probe as well their
offsets in the binary.

Signed-off-by: Francis Deslauriers <francis.deslauriers@efficios.com>
Signed-off-by: Erica Bugden <ebugden@efficios.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
include/lttng/lttng-error.h
src/common/error.c
src/common/lttng-elf.c
src/common/lttng-elf.h

index d1e9126a6eb4e7f7a1e41d43213564c66da18a3f..c53b6ceac48a5ddbb6a4ca197f78fa2597da7ff6 100644 (file)
@@ -160,6 +160,7 @@ enum lttng_error_code {
        LTTNG_ERR_AGENT_TRACING_DISABLED = 137, /* Agent tracing disabled. */
        LTTNG_ERR_PROBE_LOCATION_INVAL   = 138, /* Invalid userspace probe location. */
        LTTNG_ERR_ELF_PARSING            = 139, /* ELF parsing error. */
        LTTNG_ERR_AGENT_TRACING_DISABLED = 137, /* Agent tracing disabled. */
        LTTNG_ERR_PROBE_LOCATION_INVAL   = 138, /* Invalid userspace probe location. */
        LTTNG_ERR_ELF_PARSING            = 139, /* ELF parsing error. */
+       LTTNG_ERR_SDT_PROBE_SEMAPHORE    = 140, /* SDT probe guarded by a semaphore. */
 
        /* MUST be last element */
        LTTNG_ERR_NR,                           /* Last element */
 
        /* MUST be last element */
        LTTNG_ERR_NR,                           /* Last element */
index 2b08a8ed053278416ed78d1826e0b32f2a34c8bb..076321437fc5df3db545f3df3e9968e3d0389551 100644 (file)
@@ -201,6 +201,7 @@ static const char *error_string_array[] = {
        [ ERROR_INDEX(LTTNG_ERR_AGENT_TRACING_DISABLED) ] = "Session daemon agent tracing is disabled",
        [ ERROR_INDEX(LTTNG_ERR_PROBE_LOCATION_INVAL) ] = "Invalid userspace probe location",
        [ ERROR_INDEX(LTTNG_ERR_ELF_PARSING) ] = "ELF parsing error",
        [ ERROR_INDEX(LTTNG_ERR_AGENT_TRACING_DISABLED) ] = "Session daemon agent tracing is disabled",
        [ ERROR_INDEX(LTTNG_ERR_PROBE_LOCATION_INVAL) ] = "Invalid userspace probe location",
        [ ERROR_INDEX(LTTNG_ERR_ELF_PARSING) ] = "ELF parsing error",
+       [ ERROR_INDEX(LTTNG_ERR_SDT_PROBE_SEMAPHORE) ] = "SDT probe guarded by a semaphore",
 
        /* Last element */
        [ ERROR_INDEX(LTTNG_ERR_NR) ] = "Unknown error code"
 
        /* Last element */
        [ ERROR_INDEX(LTTNG_ERR_NR) ] = "Unknown error code"
index 779beee012929c5fa3a927f78a5a15cb0b527b3e..47dc89900237f4e88aa537ec8a8d6be548c95998 100644 (file)
@@ -48,6 +48,8 @@
 #define NATIVE_ELF_ENDIANNESS ELFDATA2MSB
 #endif
 
 #define NATIVE_ELF_ENDIANNESS ELFDATA2MSB
 #endif
 
+#define next_4bytes_boundary(x) (typeof(x)) ((((uint64_t)x) + 3) & ~0x03)
+
 #define bswap(x)                               \
        do {                                    \
                switch (sizeof(x)) {            \
 #define bswap(x)                               \
        do {                                    \
                switch (sizeof(x)) {            \
@@ -856,3 +858,189 @@ destroy_elf:
 end:
        return ret;
 }
 end:
        return ret;
 }
+
+/*
+ * Compute the offsets of SDT probes from the begining of the ELF binary.
+ *
+ * On success, returns 0 and the nb_probes parameter is set to the number of
+ * offsets found and the offsets parameter points to an array of offsets where
+ * the SDT probes are.
+ * On failure, returns -1.
+ */
+int lttng_elf_get_sdt_probe_offsets(int fd, const char *provider_name,
+               const char *probe_name, uint64_t **offsets, uint32_t *nb_probes)
+{
+       int ret = 0, nb_match = 0;
+       struct lttng_elf_shdr *stap_note_section_hdr = NULL;
+       struct lttng_elf *elf = NULL;
+       char *stap_note_section_data = NULL;
+       char *curr_note_section_begin, *curr_data_ptr, *curr_probe, *curr_provider;
+       char *next_note_ptr, *curr_desc_beg;
+       uint32_t name_size, desc_size, note_type;
+       uint64_t curr_probe_location, curr_probe_offset, curr_semaphore_location;
+       uint64_t *probe_locs = NULL, *new_probe_locs = NULL;
+
+       if (!provider_name || !probe_name || !nb_probes || !offsets) {
+               DBG("Invalid arguments.");
+               ret = LTTNG_ERR_ELF_PARSING;
+               goto error;
+       }
+
+       elf = lttng_elf_create(fd);
+       if (!elf) {
+               DBG("Error allocation ELF.");
+               ret = LTTNG_ERR_ELF_PARSING;
+               goto error;
+       }
+
+       /* Get the stap note section header. */
+       ret = lttng_elf_get_section_hdr_by_name(elf, NOTE_STAPSDT_SECTION_NAME,
+                       &stap_note_section_hdr);
+       if (ret) {
+               DBG("Cannot get ELF stap note section.");
+               goto destroy_elf_error;
+       }
+
+       /* Get the data associated with the stap note section. */
+       stap_note_section_data = lttng_elf_get_section_data(elf, stap_note_section_hdr);
+       if (stap_note_section_data == NULL) {
+               DBG("Cannot get ELF stap note section data.");
+               ret = LTTNG_ERR_ELF_PARSING;
+               goto destroy_elf_error;
+       }
+
+       curr_data_ptr = stap_note_section_data;
+       next_note_ptr = stap_note_section_data;
+       curr_note_section_begin = stap_note_section_data;
+
+       *offsets = NULL;
+       while (1) {
+               curr_data_ptr = next_note_ptr;
+               /* Check if we have reached the end of the note section. */
+               if (curr_data_ptr >=
+                               curr_note_section_begin + stap_note_section_hdr->sh_size) {
+                       *nb_probes = nb_match;
+                       *offsets = probe_locs;
+                       ret = 0;
+                       break;
+               }
+               /* Get name size field. */
+               name_size = next_4bytes_boundary(*(uint32_t*) curr_data_ptr);
+               curr_data_ptr += sizeof(uint32_t);
+
+               /* Sanity check; a zero name_size is reserved. */
+               if (name_size == 0) {
+                       DBG("Invalid name size field in SDT probe descriptions"
+                               "section.");
+                       ret = -1;
+                       goto realloc_error;
+               }
+
+               /* Get description size field. */
+               desc_size = next_4bytes_boundary(*(uint32_t*) curr_data_ptr);
+               curr_data_ptr += sizeof(uint32_t);
+
+               /* Get type field. */
+               note_type = *(uint32_t *) curr_data_ptr;
+               curr_data_ptr += sizeof(uint32_t);
+
+               /*
+                * Move the pointer to the next note to be ready for the next
+                * iteration. The current note is made of 3 unsigned 32bit
+                * integers (name size, descriptor size and note type), the
+                * name and the descriptor. To move to the next note, we move
+                * the pointer according to those values.
+                */
+               next_note_ptr = next_note_ptr +
+                       (3 * sizeof(uint32_t)) + desc_size + name_size;
+
+               /*
+                * Move ptr to the end of the name string (we don't need it)
+                * and go to the next 4 byte alignement.
+                */
+               if (note_type != NOTE_STAPSDT_TYPE ||
+                       strncmp(curr_data_ptr, NOTE_STAPSDT_NAME, name_size) != 0) {
+                       continue;
+               }
+
+               curr_data_ptr += name_size;
+
+               /* Get description field. */
+               curr_desc_beg = curr_data_ptr;
+
+               /* Get probe location.  */
+               curr_probe_location = *(uint64_t *) curr_data_ptr;
+               curr_data_ptr += sizeof(uint64_t);
+
+               /* Pass over the base. Not needed. */
+               curr_data_ptr += sizeof(uint64_t);
+
+               /* Get semaphore location. */
+               curr_semaphore_location = *(uint64_t *) curr_data_ptr;
+               curr_data_ptr += sizeof(uint64_t);
+               /* Get provider name. */
+               curr_provider = curr_data_ptr;
+               curr_data_ptr += strlen(curr_provider) + 1;
+
+               /* Get probe name. */
+               curr_probe = curr_data_ptr;
+               curr_data_ptr += strlen(curr_probe) + 1;
+
+               curr_data_ptr = curr_desc_beg + desc_size;
+
+               /* Check if the provider and probe name match */
+               if (strcmp(provider_name, curr_provider) == 0 &&
+                               strcmp(probe_name, curr_probe) == 0) {
+                       int new_size;
+
+                       /*
+                        * We currently don't support SDT probes with semaphores. Return
+                        * success as we found a matching probe but it's guarded by a
+                        * semaphore.
+                        */
+                       if (curr_semaphore_location != 0) {
+                               ret = LTTNG_ERR_SDT_PROBE_SEMAPHORE;
+                               goto end;
+                       }
+
+                       new_size = (++nb_match) * sizeof(uint64_t);
+
+                       /*
+                        * Found a match with not semaphore, we need to copy the
+                        * probe_location to the output parameter.
+                        */
+                       new_probe_locs = realloc(probe_locs, new_size);
+                       if (!new_probe_locs) {
+                               /* Error allocating a larger buffer */
+                               DBG("Allocation error in SDT.");
+                               ret = LTTNG_ERR_NOMEM;
+                               goto realloc_error;
+                       }
+                       probe_locs = new_probe_locs;
+                       new_probe_locs = NULL;
+
+                       /*
+                        * Use the virtual address of the probe to compute the offset of
+                        * this probe from the beginning of the executable file.
+                        */
+                       ret = lttng_elf_convert_addr_in_text_to_offset(elf,
+                                       curr_probe_location, &curr_probe_offset);
+                       if (ret) {
+                               DBG("Conversion error in SDT.");
+                               goto realloc_error;
+                       }
+
+                       probe_locs[nb_match - 1] = curr_probe_offset;
+               }
+       }
+
+end:
+       free(stap_note_section_data);
+destroy_elf_error:
+       lttng_elf_destroy(elf);
+error:
+       return ret;
+realloc_error:
+       free(probe_locs);
+       goto end;
+}
index 9258072393d504b898282613057e0bf8d2c892bd..c3e6eba671168f44739a912048270dca28601fbf 100644 (file)
@@ -21,4 +21,7 @@
 
 int lttng_elf_get_symbol_offset(int fd, char *symbol, uint64_t *offset);
 
 
 int lttng_elf_get_symbol_offset(int fd, char *symbol, uint64_t *offset);
 
+int lttng_elf_get_sdt_probe_offsets(int fd, const char *provider_name,
+               const char *probe_name, uint64_t **offsets, uint32_t *nb_probe);
+
 #endif /* _LTTNG_ELF_H */
 #endif /* _LTTNG_ELF_H */
This page took 0.030287 seconds and 5 git commands to generate.