X-Git-Url: https://git.lttng.org/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fcommon%2Flttng-elf.c;h=b2aa88487e1dff286c21d0442f6cdf175a68681f;hp=779beee012929c5fa3a927f78a5a15cb0b527b3e;hb=22fae25a70cc5e87ab76e5e2071c88c0c181e2c3;hpb=d0927b411543c173c4fb83abf785fd71a9d29ed1 diff --git a/src/common/lttng-elf.c b/src/common/lttng-elf.c index 779beee01..b2aa88487 100644 --- a/src/common/lttng-elf.c +++ b/src/common/lttng-elf.c @@ -38,6 +38,8 @@ #define TEXT_SECTION_NAME ".text" #define SYMBOL_TAB_SECTION_NAME ".symtab" #define STRING_TAB_SECTION_NAME ".strtab" +#define DYNAMIC_SYMBOL_TAB_SECTION_NAME ".dynsym" +#define DYNAMIC_STRING_TAB_SECTION_NAME ".dynstr" #define NOTE_STAPSDT_SECTION_NAME ".note.stapsdt" #define NOTE_STAPSDT_NAME "stapsdt" #define NOTE_STAPSDT_TYPE 3 @@ -48,17 +50,19 @@ #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)) { \ case 8: \ - x = be64toh(x); \ + x = be64toh((uint64_t)x); \ break; \ case 4: \ - x = be32toh(x); \ + x = be32toh((uint32_t)x); \ break; \ case 2: \ - x = be16toh(x); \ + x = be16toh((uint16_t)x); \ break; \ case 1: \ break; \ @@ -305,39 +309,32 @@ error: * Retrieve the nth (where n is the `index` argument) shdr (section * header) from the given elf instance. * - * A pointer to the shdr is returned on success, NULL on failure. + * 0 is returned on succes, -1 on failure. */ static -struct lttng_elf_shdr *lttng_elf_get_section_hdr(struct lttng_elf *elf, - uint16_t index) +int lttng_elf_get_section_hdr(struct lttng_elf *elf, + uint16_t index, struct lttng_elf_shdr *out_header) { - struct lttng_elf_shdr *section_header = NULL; int ret = 0; if (!elf) { + ret = -1; goto error; } if (index >= elf->ehdr->e_shnum) { + ret = -1; goto error; } - section_header = zmalloc(sizeof(struct lttng_elf_shdr)); - if (!section_header) { - goto error; - } - - ret = populate_section_header(elf, section_header, index); + ret = populate_section_header(elf, out_header, index); if (ret) { - ret = LTTNG_ERR_ELF_PARSING; DBG("Error populating section header."); goto error; } - return section_header; error: - free(section_header); - return NULL; + return ret; } /* @@ -531,7 +528,7 @@ end: static struct lttng_elf *lttng_elf_create(int fd) { - struct lttng_elf_shdr *section_names_shdr; + struct lttng_elf_shdr section_names_shdr; struct lttng_elf *elf = NULL; int ret; @@ -556,15 +553,14 @@ struct lttng_elf *lttng_elf_create(int fd) goto error; } - section_names_shdr = lttng_elf_get_section_hdr(elf, elf->ehdr->e_shstrndx); - if (!section_names_shdr) { + ret = lttng_elf_get_section_hdr( + elf, elf->ehdr->e_shstrndx, §ion_names_shdr); + if (ret) { goto error; } - elf->section_names_offset = section_names_shdr->sh_offset; - elf->section_names_size = section_names_shdr->sh_size; - - free(section_names_shdr); + elf->section_names_offset = section_names_shdr.sh_offset; + elf->section_names_size = section_names_shdr.sh_size; return elf; error: @@ -603,15 +599,19 @@ void lttng_elf_destroy(struct lttng_elf *elf) static int lttng_elf_get_section_hdr_by_name(struct lttng_elf *elf, - const char *section_name, struct lttng_elf_shdr **section_hdr) + const char *section_name, struct lttng_elf_shdr *section_hdr) { int i; char *curr_section_name; + for (i = 0; i < elf->ehdr->e_shnum; ++i) { - *section_hdr = lttng_elf_get_section_hdr(elf, i); - curr_section_name = lttng_elf_get_section_name(elf, - (*section_hdr)->sh_name); + int ret = lttng_elf_get_section_hdr(elf, i, section_hdr); + if (ret) { + break; + } + curr_section_name = lttng_elf_get_section_name(elf, + section_hdr->sh_name); if (!curr_section_name) { continue; } @@ -675,7 +675,7 @@ int lttng_elf_convert_addr_in_text_to_offset(struct lttng_elf *elf_handle, off_t text_section_addr_beg; off_t text_section_addr_end; off_t offset_in_section; - struct lttng_elf_shdr *text_section_hdr = NULL; + struct lttng_elf_shdr text_section_hdr; if (!elf_handle) { DBG("Invalid ELF handle."); @@ -692,9 +692,10 @@ int lttng_elf_convert_addr_in_text_to_offset(struct lttng_elf *elf_handle, goto error; } - text_section_offset = text_section_hdr->sh_offset; - text_section_addr_beg = text_section_hdr->sh_addr; - text_section_addr_end = text_section_addr_beg + text_section_hdr->sh_size; + text_section_offset = text_section_hdr.sh_offset; + text_section_addr_beg = text_section_hdr.sh_addr; + text_section_addr_end = + text_section_addr_beg + text_section_hdr.sh_size; /* * Verify that the address is within the .text section boundaries. @@ -735,8 +736,9 @@ int lttng_elf_get_symbol_offset(int fd, char *symbol, uint64_t *offset) char *curr_sym_str = NULL; char *symbol_table_data = NULL; char *string_table_data = NULL; - struct lttng_elf_shdr *symtab_hdr = NULL; - struct lttng_elf_shdr *strtab_hdr = NULL; + char *string_table_name = NULL; + struct lttng_elf_shdr symtab_hdr; + struct lttng_elf_shdr strtab_hdr; struct lttng_elf *elf = NULL; if (!symbol || !offset ) { @@ -750,16 +752,31 @@ int lttng_elf_get_symbol_offset(int fd, char *symbol, uint64_t *offset) goto end; } - /* Get the symbol table section header. */ + /* + * The .symtab section might not exist on stripped binaries. + * Try to get the symbol table section header first. If it's absent, + * try to get the dynamic symbol table. All symbols in the dynamic + * symbol tab are in the (normal) symbol table if it exists. + */ ret = lttng_elf_get_section_hdr_by_name(elf, SYMBOL_TAB_SECTION_NAME, &symtab_hdr); if (ret) { - DBG("Cannot get ELF Symbol Table section."); - ret = LTTNG_ERR_ELF_PARSING; - goto destroy_elf; + DBG("Cannot get ELF Symbol Table section. Trying to get ELF Dynamic Symbol Table section."); + /* Get the dynamic symbol table section header. */ + ret = lttng_elf_get_section_hdr_by_name(elf, DYNAMIC_SYMBOL_TAB_SECTION_NAME, + &symtab_hdr); + if (ret) { + DBG("Cannot get ELF Symbol Table nor Dynamic Symbol Table sections."); + ret = LTTNG_ERR_ELF_PARSING; + goto destroy_elf; + } + string_table_name = DYNAMIC_STRING_TAB_SECTION_NAME; + } else { + string_table_name = STRING_TAB_SECTION_NAME; } + /* Get the data associated with the symbol table section. */ - symbol_table_data = lttng_elf_get_section_data(elf, symtab_hdr); + symbol_table_data = lttng_elf_get_section_data(elf, &symtab_hdr); if (symbol_table_data == NULL) { DBG("Cannot get ELF Symbol Table data."); ret = LTTNG_ERR_ELF_PARSING; @@ -767,7 +784,7 @@ int lttng_elf_get_symbol_offset(int fd, char *symbol, uint64_t *offset) } /* Get the string table section header. */ - ret = lttng_elf_get_section_hdr_by_name(elf, STRING_TAB_SECTION_NAME, + ret = lttng_elf_get_section_hdr_by_name(elf, string_table_name, &strtab_hdr); if (ret) { DBG("Cannot get ELF string table section."); @@ -775,7 +792,7 @@ int lttng_elf_get_symbol_offset(int fd, char *symbol, uint64_t *offset) } /* Get the data associated with the string table section. */ - string_table_data = lttng_elf_get_section_data(elf, strtab_hdr); + string_table_data = lttng_elf_get_section_data(elf, &strtab_hdr); if (string_table_data == NULL) { DBG("Cannot get ELF string table section data."); ret = LTTNG_ERR_ELF_PARSING; @@ -783,7 +800,7 @@ int lttng_elf_get_symbol_offset(int fd, char *symbol, uint64_t *offset) } /* Get the number of symbol in the table for the iteration. */ - sym_count = symtab_hdr->sh_size / symtab_hdr->sh_entsize; + sym_count = symtab_hdr.sh_size / symtab_hdr.sh_entsize; /* Loop over all symbol. */ for (sym_idx = 0; sym_idx < sym_count; sym_idx++) { @@ -842,7 +859,7 @@ int lttng_elf_get_symbol_offset(int fd, char *symbol, uint64_t *offset) */ ret = lttng_elf_convert_addr_in_text_to_offset(elf, addr, offset); if (ret) { - DBG("Cannot convet addr to offset."); + DBG("Cannot convert addr to offset."); goto free_string_table_data; } @@ -856,3 +873,184 @@ destroy_elf: 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; + 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; + 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; + } + + 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 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; + + /* 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 realloc_error; + } + + 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; +}