X-Git-Url: http://git.efficios.com/?p=babeltrace.git;a=blobdiff_plain;f=lib%2Fso-info.c;h=93d7167fee60244932fc15634a3fa797a5b54352;hp=404425dcf0ba7e98808427f8a4ea28ed9392d367;hb=b7b61ced2a4d4e3222640ad20e6655cb4379c012;hpb=3be1e3c98864ad12cab2e53c42db5252193367f5 diff --git a/lib/so-info.c b/lib/so-info.c index 404425dc..93d7167f 100644 --- a/lib/so-info.c +++ b/lib/so-info.c @@ -40,6 +40,7 @@ #include #include #include +#include /* * An address printed in hex is at most 20 bytes (16 for 64-bits + @@ -64,10 +65,9 @@ int so_info_init(void) BT_HIDDEN struct so_info *so_info_create(const char *path, uint64_t low_addr, - uint64_t memsz) + uint64_t memsz, bool is_pic) { struct so_info *so = NULL; - GElf_Ehdr *ehdr = NULL; if (!path) { goto error; @@ -78,51 +78,25 @@ struct so_info *so_info_create(const char *path, uint64_t low_addr, goto error; } - so->elf_path = strdup(path); - if (!so->elf_path) { - goto error; - } - - so->elf_fd = open(path, O_RDONLY); - if (so->elf_fd < 0) { - fprintf(stderr, "Failed to open %s\n", path); - goto error; - } - - so->elf_file = elf_begin(so->elf_fd, ELF_C_READ, NULL); - if (!so->elf_file) { - fprintf(stderr, "elf_begin failed: %s\n", elf_errmsg(-1)); - goto error; - } - - if (elf_kind(so->elf_file) != ELF_K_ELF) { - fprintf(stderr, "Error: %s is not an ELF object\n", - so->elf_path); - goto error; - } - - ehdr = g_new0(GElf_Ehdr, 1); - if (!ehdr) { - goto error; + if (opt_debug_info_target_prefix) { + so->elf_path = g_build_path("/", opt_debug_info_target_prefix, + path, NULL); + } else { + so->elf_path = strdup(path); } - if (!gelf_getehdr(so->elf_file, ehdr)) { - fprintf(stderr, "Error: couldn't get ehdr for %s\n", - so->elf_path); + if (!so->elf_path) { goto error; } - /* Position independent code has an e_type value of ET_DYN. */ - so->is_pic = ehdr->e_type == ET_DYN; + so->is_pic = is_pic; so->memsz = memsz; so->low_addr = low_addr; so->high_addr = so->low_addr + so->memsz; - g_free(ehdr); return so; error: - g_free(ehdr); so_info_destroy(so); return NULL; } @@ -149,6 +123,7 @@ void so_info_destroy(struct so_info *so) g_free(so); } + BT_HIDDEN int so_info_set_build_id(struct so_info *so, uint8_t *build_id, size_t build_id_len) @@ -512,6 +487,51 @@ end: return ret; } +/** + * Initialize the ELF file for a given executable. + * + * @param so so_info instance + * @returns 0 on success, -1 on failure + */ +static +int so_info_set_elf_file(struct so_info *so) +{ + int elf_fd; + Elf *elf_file = NULL; + + if (!so) { + goto error; + } + + elf_fd = open(so->elf_path, O_RDONLY); + if (elf_fd < 0) { + fprintf(stderr, "Failed to open %s\n", so->elf_path); + goto error; + } + + elf_file = elf_begin(elf_fd, ELF_C_READ, NULL); + if (!elf_file) { + fprintf(stderr, "elf_begin failed: %s\n", elf_errmsg(-1)); + goto error; + } + + if (elf_kind(elf_file) != ELF_K_ELF) { + fprintf(stderr, "Error: %s is not an ELF object\n", + so->elf_path); + goto error; + } + + so->elf_fd = elf_fd; + so->elf_file = elf_file; + return 0; + +error: + close(elf_fd); + elf_end(elf_file); + return -1; +} + + BT_HIDDEN void source_location_destroy(struct source_location *src_loc) { @@ -522,6 +542,56 @@ void source_location_destroy(struct source_location *src_loc) free(src_loc->filename); g_free(src_loc); } +/** + * Append a string representation of an address offset to an existing + * string. + * + * On success, the out parameter `result` will contain the base string + * followed by the offset string of the form "+0x1234". On failure, + * `result` remains unchanged. + * + * @param base_str The string to which to append an offset string + * @param low_addr The lower virtual memory address, the base from + * which the offset is computed + * @param high_addr The higher virtual memory address + * @param result Out parameter, the base string followed by the + * offset string + * @returns 0 on success, -1 on failure + */ +static +int so_info_append_offset_str(const char *base_str, uint64_t low_addr, + uint64_t high_addr, char **result) +{ + int ret; + uint64_t offset; + char *_result = NULL; + char offset_str[ADDR_STR_LEN]; + + if (!base_str || !result) { + goto error; + } + + offset = high_addr - low_addr; + + _result = malloc(strlen(base_str) + ADDR_STR_LEN); + if (!_result) { + goto error; + } + + ret = snprintf(offset_str, ADDR_STR_LEN, "+%#0" PRIx64, offset); + if (ret < 0) { + goto error; + } + strcpy(_result, base_str); + strcat(_result, offset_str); + *result = _result; + + return 0; + +error: + free(_result); + return -1; +} /** * Try to find the symbol closest to an address within a given ELF @@ -656,8 +726,15 @@ int so_info_lookup_elf_function_name(struct so_info *so, uint64_t addr, GElf_Sym *sym = NULL; GElf_Shdr *shdr = NULL; char *sym_name = NULL; - char *_func_name = NULL; - char offset_str[ADDR_STR_LEN]; + + /* Set ELF file if it hasn't been accessed yet. */ + if (!so->elf_file) { + ret = so_info_set_elf_file(so); + if (ret) { + /* Failed to set ELF file. */ + goto error; + } + } scn = elf_nextscn(so->elf_file, scn); if (!scn) { @@ -681,16 +758,11 @@ int so_info_lookup_elf_function_name(struct so_info *so, uint64_t addr, goto error; } - snprintf(offset_str, ADDR_STR_LEN, "+%#0" PRIx64, - addr - sym->st_value); - _func_name = malloc(strlen(sym_name) + ADDR_STR_LEN); - if (!_func_name) { + ret = so_info_append_offset_str(sym_name, sym->st_value, addr, + func_name); + if (ret) { goto error; } - - strcpy(_func_name, sym_name); - strcat(_func_name, offset_str); - *func_name = _func_name; } g_free(shdr); @@ -700,7 +772,6 @@ int so_info_lookup_elf_function_name(struct so_info *so, uint64_t addr, error: g_free(shdr); g_free(sym); - free(_func_name); return -1; } @@ -722,7 +793,6 @@ int so_info_lookup_cu_function_name(struct bt_dwarf_cu *cu, uint64_t addr, char **func_name) { int ret = 0, found = 0; - char *_func_name = NULL; struct bt_dwarf_die *die = NULL; if (!cu || !func_name) { @@ -755,12 +825,24 @@ int so_info_lookup_cu_function_name(struct bt_dwarf_cu *cu, uint64_t addr, } if (found) { - ret = bt_dwarf_die_get_name(die, &_func_name); + uint64_t low_addr = 0; + char *die_name = NULL; + + ret = bt_dwarf_die_get_name(die, &die_name); if (ret) { goto error; } - *func_name = _func_name; + ret = dwarf_lowpc(die->dwarf_die, &low_addr); + if (ret) { + goto error; + } + + ret = so_info_append_offset_str(die_name, low_addr, addr, + func_name); + if (ret) { + goto error; + } } bt_dwarf_die_destroy(die); @@ -863,14 +945,39 @@ int so_info_lookup_function_name(struct so_info *so, uint64_t addr, ret = so_info_lookup_dwarf_function_name(so, addr, &_func_name); } - if (ret) { + if (ret || !_func_name) { goto error; } - if (_func_name) { - *func_name = _func_name; + *func_name = _func_name; + return 0; + +error: + return -1; +} + +BT_HIDDEN +int so_info_get_bin_loc(struct so_info *so, uint64_t addr, char **bin_loc) +{ + int ret = 0; + char *_bin_loc = NULL; + + if (!so || !bin_loc) { + goto error; + } + + if (so->is_pic) { + addr -= so->low_addr; + ret = asprintf(&_bin_loc, "+%#0" PRIx64, addr); + } else { + ret = asprintf(&_bin_loc, "@%#0" PRIx64, addr); + } + + if (ret == -1 || !_bin_loc) { + goto error; } + *bin_loc = _bin_loc; return 0; error: