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;
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 (!gelf_getehdr(so->elf_file, ehdr)) {
- fprintf(stderr, "Error: couldn't get ehdr for %s\n",
- 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;
}
g_free(so);
}
+
BT_HIDDEN
int so_info_set_build_id(struct so_info *so, uint8_t *build_id,
size_t build_id_len)
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)
{
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
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) {
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);
error:
g_free(shdr);
g_free(sym);
- free(_func_name);
return -1;
}
char **func_name)
{
int ret = 0, found = 0;
- char *_func_name = NULL;
struct bt_dwarf_die *die = NULL;
if (!cu || !func_name) {
}
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);
}
BT_HIDDEN
-int so_info_lookup_function_name(struct so_info *so, uint64_t ip,
+int so_info_lookup_function_name(struct so_info *so, uint64_t addr,
char **func_name)
{
int ret = 0;
char *_func_name = NULL;
- uint64_t relative_addr;
if (!so || !func_name) {
goto error;
}
}
- if (!so_info_has_address(so, ip)) {
+ if (!so_info_has_address(so, addr)) {
goto error;
}
- relative_addr = ip - so->low_addr;
/*
* Addresses in ELF and DWARF are relative to base address for
* PIC, so make the address argument relative too if needed.
*/
+ if (so->is_pic) {
+ addr -= so->low_addr;
+ }
+
if (so->is_elf_only) {
- ret = so_info_lookup_elf_function_name(so,
- so->is_pic ? relative_addr : ip,
- &_func_name);
+ ret = so_info_lookup_elf_function_name(so, addr, &_func_name);
} else {
- ret = so_info_lookup_dwarf_function_name(so,
- so->is_pic ? relative_addr : ip,
- &_func_name);
+ ret = so_info_lookup_dwarf_function_name(so, addr, &_func_name);
}
- if (ret) {
+ if (ret || !_func_name) {
goto error;
}
- if (!_func_name) {
- /*
- * Can't map to a function; fallback to a generic output of the
- * form binary+/@address.
- *
- * FIXME check position independence flag.
- */
- const char *binary_name = get_filename_from_path(so->elf_path);
+ *func_name = _func_name;
+ return 0;
- ret = asprintf(&_func_name, "%s+%#0" PRIx64, binary_name,
- relative_addr);
- if (!_func_name) {
- goto error;
- }
+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;
}
- *func_name = _func_name;
+ 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: