#include <glib.h>
+#include <babeltrace2/common-internal.h>
+
#include "bin-info.h"
#include "crc32.h"
#include "dwarf.h"
}
if (target_prefix) {
- bin->elf_path = g_build_path("/", target_prefix,
- path, NULL);
+ bin->elf_path = g_build_filename(target_prefix, path, NULL);
} else {
bin->elf_path = g_strdup(path);
}
BT_LOGD("Failed to open %s", bin->elf_path);
goto error;
}
+ bin->elf_handle = elf_handle;
- elf_file = elf_begin(bt_fd_cache_handle_get_fd(elf_handle),
+ elf_file = elf_begin(bt_fd_cache_handle_get_fd(bin->elf_handle),
ELF_C_READ, NULL);
if (!elf_file) {
BT_LOGE("elf_begin failed: %s", elf_errmsg(-1));
goto error;
}
+ bin->elf_file = elf_file;
+
if (elf_kind(elf_file) != ELF_K_ELF) {
BT_LOGE("Error: %s is not an ELF object", bin->elf_path);
goto error;
}
- bin->elf_handle = elf_handle;
- bin->elf_file = elf_file;
return 0;
error:
}
/**
- * From a note section data buffer, check if it is a build id note.
+ * From a note section data struct, check if it is a build id note.
*
- * @param buf Pointer to a note section
+ * @param note_data Pointer to a note section
*
* @returns 1 on match, 0 if `buf` does not contain a
* valid build id note
*/
static
-int is_build_id_note_section(uint8_t *buf)
+int is_build_id_note_section(Elf_Data *note_data)
{
+ size_t name_offset, desc_offset;
+ GElf_Nhdr note_header;
int ret = 0;
- uint32_t name_sz, desc_sz, note_type;
- /* The note section header has 3 32bit integer for the following:
- * - Section name size
- * - Description size
- * - Note type
+ /*
+ * Discard the return value as it contains the size of the note section
+ * and we don't need it.
*/
- name_sz = (uint32_t) *buf;
- buf += sizeof(name_sz);
+ (void) gelf_getnote(note_data, 0, ¬e_header, &name_offset,
+ &desc_offset);
- buf += sizeof(desc_sz);
-
- note_type = (uint32_t) *buf;
- buf += sizeof(note_type);
+ /*
+ * Check the note name length. The name_sz field includes the
+ * terminating null byte.
+ */
+ if (note_header.n_namesz != sizeof(BUILD_ID_NOTE_NAME)) {
+ goto invalid;
+ }
/* Check the note type. */
- if (note_type != NT_GNU_BUILD_ID) {
+ if (note_header.n_type != NT_GNU_BUILD_ID) {
goto invalid;
}
/* Check the note name. */
- if (memcmp(buf, BUILD_ID_NOTE_NAME, name_sz) != 0) {
+ if (memcmp(note_data->d_buf + name_offset, BUILD_ID_NOTE_NAME,
+ note_header.n_namesz) != 0) {
goto invalid;
}
}
/**
- * From a build id note section data buffer, check if the build id it contains
+ * From a build id note section data struct, check if the build id it contains
* is identical to the build id passed as parameter.
*
- * @param file_build_id_note Pointer to the file build id note section.
+ * @param note_data Pointer to the file build id note section.
* @param build_id Pointer to a build id to compare to.
* @param build_id_len length of the build id.
*
* @returns 1 on match, 0 otherwise.
*/
static
-int is_build_id_note_section_matching(uint8_t *file_build_id_note,
+int is_build_id_note_section_matching(Elf_Data *note_data,
uint8_t *build_id, size_t build_id_len)
{
- uint32_t name_sz, desc_sz, note_type;
+ size_t name_offset, desc_offset;
+ GElf_Nhdr note_header;
if (build_id_len <= 0) {
goto end;
}
- /* The note section header has 3 32bit integer for the following:
- * - Section name size
- * - Description size
- * - Note type
- */
- name_sz = (uint32_t) *file_build_id_note;
- file_build_id_note += sizeof(name_sz);
- file_build_id_note += sizeof(desc_sz);
- file_build_id_note += sizeof(note_type);
-
/*
- * Move the pointer pass the name char array. This corresponds to the
- * beginning of the description section. The description is the build
- * id in the case of a build id note.
+ * Discard the return value as it contains the size of the note section
+ * and we don't need it.
*/
- file_build_id_note += name_sz;
+ (void) gelf_getnote(note_data, 0, ¬e_header, &name_offset,
+ &desc_offset);
/*
* Compare the binary build id with the supplied build id.
*/
- if (memcmp(build_id, file_build_id_note, build_id_len) == 0) {
+ if (memcmp(build_id, note_data->d_buf + desc_offset,
+ build_id_len) == 0) {
return 1;
}
end:
{
int ret, is_build_id, is_matching = 0;
Elf_Scn *curr_section = NULL, *next_section = NULL;
- Elf_Data *note_data = NULL;
- GElf_Shdr *curr_section_hdr = NULL;
+ GElf_Shdr curr_section_hdr;
if (!bin->build_id) {
goto error;
}
}
- curr_section_hdr = g_new0(GElf_Shdr, 1);
- if (!curr_section_hdr) {
- goto error;
- }
-
next_section = elf_nextscn(bin->elf_file, curr_section);
if (!next_section) {
goto error;
}
while (next_section) {
+ Elf_Data *note_data = NULL;
+
curr_section = next_section;
next_section = elf_nextscn(bin->elf_file, curr_section);
- curr_section_hdr = gelf_getshdr(curr_section, curr_section_hdr);
-
- if (!curr_section_hdr) {
+ if (!gelf_getshdr(curr_section, &curr_section_hdr)) {
goto error;
}
- if (curr_section_hdr->sh_type != SHT_NOTE) {
+ if (curr_section_hdr.sh_type != SHT_NOTE) {
continue;
}
+ /*
+ * elf_getdata() translates the data to native byte order.
+ */
note_data = elf_getdata(curr_section, NULL);
if (!note_data) {
goto error;
}
/* Check if the note is of the build-id type. */
- is_build_id = is_build_id_note_section(note_data->d_buf);
+ is_build_id = is_build_id_note_section(note_data);
if (!is_build_id) {
continue;
}
* Compare the build id of the on-disk file and
* the build id recorded in the trace.
*/
- is_matching = is_build_id_note_section_matching(note_data->d_buf,
- bin->build_id, bin->build_id_len);
+ is_matching = is_build_id_note_section_matching(
+ note_data, bin->build_id, bin->build_id_len);
if (!is_matching) {
break;
}
}
error:
- g_free(curr_section_hdr);
return is_matching;
}
int bin_info_set_dwarf_info_build_id(struct bin_info *bin)
{
int i = 0, ret = 0;
- char *path = NULL, *build_id_file = NULL;
+ char *path = NULL, *build_id_prefix_dir = NULL, *build_id_file = NULL;
const char *dbg_dir = NULL;
size_t build_id_char_len, build_id_suffix_char_len, build_id_file_len;
dbg_dir = bin->debug_info_dir ? bin->debug_info_dir : DEFAULT_DEBUG_DIR;
- /* 2 characters per byte printed in hex, +1 for '/' and +1 for '\0' */
- build_id_char_len = (2 * bin->build_id_len) + 1;
+ /*
+ * The prefix dir is the first byte of the build id, represented in
+ * lowercase hex as two characters per byte, +1 for '\0'.
+ */
+ build_id_prefix_dir = g_new0(gchar, BUILD_ID_PREFIX_DIR_LEN + 1);
+ if (!build_id_prefix_dir) {
+ goto error;
+ }
+ g_snprintf(build_id_prefix_dir, BUILD_ID_PREFIX_DIR_LEN + 1, "%02x", bin->build_id[0]);
+
+ /*
+ * The build id file is the remaining bytes of the build id,
+ * represented in lowercase hex, as two characters per byte.
+ */
+ build_id_char_len = (2 * (bin->build_id_len - 1));
+
+ /* To which the build id suffix is added, +1 for '\0'. */
build_id_suffix_char_len = strlen(BUILD_ID_SUFFIX) + 1;
+
+ /*
+ * The resulting filename string is the concatenation of the
+ * hex build id and the suffix.
+ */
build_id_file_len = build_id_char_len + build_id_suffix_char_len;
build_id_file = g_new0(gchar, build_id_file_len);
if (!build_id_file) {
goto error;
}
- g_snprintf(build_id_file, 4, "%02x/", bin->build_id[0]);
+ /*
+ * For each byte, starting at offset 1, append two characters
+ * in lowercase hex.
+ */
for (i = 1; i < bin->build_id_len; ++i) {
- int path_idx = 3 + 2 * (i - 1);
+ int path_idx = 2 * (i - 1);
g_snprintf(&build_id_file[path_idx], 3, "%02x", bin->build_id[i]);
}
+ /* Append the suffix to the generated string, including the '\0'. */
g_snprintf(&build_id_file[build_id_char_len], build_id_suffix_char_len,
BUILD_ID_SUFFIX);
- path = g_build_path("/", dbg_dir, BUILD_ID_SUBDIR, build_id_file, NULL);
+ path = g_build_filename(dbg_dir, BUILD_ID_SUBDIR, build_id_prefix_dir, build_id_file, NULL);
if (!path) {
goto error;
}
error:
ret = -1;
end:
- free(build_id_file);
- free(path);
+ g_free(build_id_prefix_dir);
+ g_free(build_id_file);
+ g_free(path);
return ret;
}
{
int ret = 0;
const gchar *dbg_dir = NULL;
- gchar *bin_dir = NULL, *dir_name = NULL, *path = NULL;
+ gchar *bin_dir = NULL, *path = NULL;
if (!bin || !bin->dbg_link_filename) {
goto error;
}
dbg_dir = bin->debug_info_dir ? bin->debug_info_dir : DEFAULT_DEBUG_DIR;
- dir_name = g_path_get_dirname(bin->elf_path);
- if (!dir_name) {
- goto error;
- }
-
- bin_dir = g_strconcat(dir_name, "/", NULL);
+ bin_dir = g_path_get_dirname(bin->elf_path);
/* First look in the executable's dir */
- path = g_strconcat(bin_dir, bin->dbg_link_filename, NULL);
+ path = g_build_filename(bin_dir, bin->dbg_link_filename, NULL);
if (is_valid_debug_file(bin, path, bin->dbg_link_crc)) {
goto found;
/* If not found, look in .debug subdir */
g_free(path);
- path = g_strconcat(bin_dir, DEBUG_SUBDIR, bin->dbg_link_filename, NULL);
+ path = g_build_filename(bin_dir, DEBUG_SUBDIR, bin->dbg_link_filename, NULL);
if (is_valid_debug_file(bin, path, bin->dbg_link_crc)) {
goto found;
/* Lastly, look under the global debug directory */
g_free(path);
- path = g_strconcat(dbg_dir, bin_dir, bin->dbg_link_filename, NULL);
+ path = g_build_filename(dbg_dir, bin_dir, bin->dbg_link_filename, NULL);
if (is_valid_debug_file(bin, path, bin->dbg_link_crc)) {
goto found;
}
ret = -1;
end:
g_free(bin_dir);
- g_free(dir_name);
g_free(path);
return ret;
uint64_t offset;
char *_result = NULL;
-
if (!base_str || !result) {
goto error;
}
* @param cu bt_dwarf_cu instance in which to look for the address
* @param addr The address for which to look for
* @param src_loc Out parameter, the source location (filename and
- * line number) for the address
+ * line number) for the address. Set only if the address
+ * is found and resolved successfully
+ *
* @returns 0 on success, -1 on failure
*/
static
const char *filename = NULL;
Dwarf_Line *line = NULL;
Dwarf_Addr line_addr;
- int ret, line_no;
+ int ret = 0, line_no;
if (!cu || !src_loc) {
goto error;
line = dwarf_getsrc_die(die->dwarf_die, addr);
if (!line) {
- goto error;
+ /* This is not an error. The caller needs to keep looking. */
+ goto end;
}
ret = dwarf_lineaddr(line, &line_addr);
_src_loc->filename = g_strdup(filename);
}
- bt_dwarf_die_destroy(die);
-
if (_src_loc) {
*src_loc = _src_loc;
}
- return 0;
+ goto end;
error:
source_location_destroy(_src_loc);
+ ret = -1;
+end:
bt_dwarf_die_destroy(die);
- return -1;
+ return ret;
}
/**