Add --debug-info-target-prefix
[babeltrace.git] / lib / so-info.c
index a5ddfe51ed866a76ac1a71252140829b04970dd4..93d7167fee60244932fc15634a3fa797a5b54352 100644 (file)
@@ -68,7 +68,6 @@ struct so_info *so_info_create(const char *path, uint64_t low_addr,
                uint64_t memsz, bool is_pic)
 {
        struct so_info *so = NULL;
-       GElf_Ehdr *ehdr = NULL;
 
        if (!path) {
                goto error;
@@ -79,37 +78,14 @@ 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;
        }
 
@@ -118,11 +94,9 @@ struct so_info *so_info_create(const char *path, uint64_t low_addr,
        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);
@@ -826,12 +908,11 @@ error:
 }
 
 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;
@@ -846,46 +927,57 @@ int so_info_lookup_function_name(struct so_info *so, uint64_t ip,
                }
        }
 
-       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:
This page took 0.027033 seconds and 4 git commands to generate.