drgn/libdrgn/elf_file.h
Omar Sandoval c7f1d0d40c libdrgn: dwarf_info: read CU DIE with libdw in DWARF index
Split DWARF is challenging for the DWARF index for a couple of reasons:

1. We need libdw to look up the split files.
2. The file name table comes from the skeleton file, but everything else
   relevant to the index comes from the split file.

(1) requires the index to use libdw to get the CU DIE. Unfortunately,
due to the overhead of libdw, this makes the indexing step 5-10% slower.
On the plus side, getting the CU DIE upfront simplifies quite a bit: we
can read the file name table, compilation directory, and str_offsets
base before indexing, which makes supporting (2) possible.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2023-07-19 10:10:08 -07:00

170 lines
4.4 KiB
C

// Copyright (c) Meta Platforms, Inc. and affiliates.
// SPDX-License-Identifier: LGPL-2.1-or-later
/**
* @file
*
* ELF files.
*
* See @ref ElfFile.
*/
#ifndef DRGN_ELF_FILE_H
#define DRGN_ELF_FILE_H
#include <elfutils/libdw.h>
#include <libelf.h>
#include <stdbool.h>
#include <stdint.h>
#include "binary_buffer.h"
#include "elf_sections.h" // IWYU pragma: export
#include "platform.h"
struct drgn_module;
/**
* @ingroup Internals
*
* @defgroup ElfFile ELF files
*
* ELF file handling.
*
* @{
*/
/**
* Read the raw data from an ELF section, decompressing it first if it is
* compressed.
*
* @warning If the section is `SHT_NOBITS`, this returns an `Elf_Data` with
* `d_size >= 0 && d_buf == NULL`.
*/
struct drgn_error *read_elf_section(Elf_Scn *scn, Elf_Data **ret);
static inline bool elf_data_contains_ptr(Elf_Data *data, const void *ptr)
{
uintptr_t bufi = (uintptr_t)data->d_buf;
uintptr_t ptri = (uintptr_t)ptr;
return ptri >= bufi && ptri - bufi < data->d_size;
}
/** An ELF file used by a @ref drgn_module. */
struct drgn_elf_file {
/** Module using this file. */
struct drgn_module *module;
/** Filesystem path to this file. */
const char *path;
/** libelf handle. */
Elf *elf;
/** libdw handle if we're using DWARF information from this file. */
Dwarf *dwarf;
/**
* Platform of this file.
*
* This should take precedence over @ref drgn_program::platform when
* parsing this file. Note that there are some cases where it doesn't
* make sense for the program and file platforms to differ (e.g., stack
* unwinding), in which case the file should be ignored if its platform
* doesn't match the program's.
*/
struct drgn_platform platform;
/** Important ELF sections. */
Elf_Scn *scns[DRGN_SECTION_INDEX_NUM];
/** Data cached for important ELF sections. */
Elf_Data *scn_data[DRGN_SECTION_INDEX_NUM_DATA];
/**
* If the file has a debugaltlink file, the debugaltlink file's
* `.debug_info` section data.
*/
Elf_Data *alt_debug_info_data;
/**
* If the file has a debugaltlink file, the debugaltlink file's
* `.debug_str` section data.
*/
Elf_Data *alt_debug_str_data;
};
struct drgn_error *drgn_elf_file_create(struct drgn_module *module,
const char *path, Elf *elf,
struct drgn_elf_file **ret);
void drgn_elf_file_destroy(struct drgn_elf_file *file);
struct drgn_error *drgn_elf_file_precache_sections(struct drgn_elf_file *file);
struct drgn_error *
drgn_elf_file_cache_section(struct drgn_elf_file *file, enum drgn_section_index scn);
static inline bool
drgn_elf_file_is_little_endian(const struct drgn_elf_file *file)
{
return drgn_platform_is_little_endian(&file->platform);
}
static inline bool drgn_elf_file_bswap(const struct drgn_elf_file *file)
{
return drgn_platform_bswap(&file->platform);
}
static inline uint8_t
drgn_elf_file_address_size(const struct drgn_elf_file *file)
{
return drgn_platform_address_size(&file->platform);
}
static inline uint64_t
drgn_elf_file_address_mask(const struct drgn_elf_file *file)
{
return drgn_platform_address_mask(&file->platform);
}
struct drgn_error *
drgn_elf_file_section_error(struct drgn_elf_file *file, Elf_Scn *scn,
Elf_Data *data, const char *ptr,
const char *message)
__attribute__((__returns_nonnull__));
struct drgn_error *
drgn_elf_file_section_errorf(struct drgn_elf_file *file, Elf_Scn *scn,
Elf_Data *data, const char *ptr,
const char *format, ...)
__attribute__((__returns_nonnull__, __format__(__printf__, 5, 6)));
struct drgn_elf_file_section_buffer {
struct binary_buffer bb;
struct drgn_elf_file *file;
Elf_Scn *scn;
Elf_Data *data;
};
struct drgn_error *drgn_elf_file_section_buffer_error(struct binary_buffer *bb,
const char *ptr,
const char *message);
static inline void
drgn_elf_file_section_buffer_init(struct drgn_elf_file_section_buffer *buffer,
struct drgn_elf_file *file, Elf_Scn *scn,
Elf_Data *data)
{
binary_buffer_init(&buffer->bb, data->d_buf, data->d_size,
drgn_elf_file_is_little_endian(file),
drgn_elf_file_section_buffer_error);
buffer->file = file;
buffer->scn = scn;
buffer->data = data;
}
static inline void
drgn_elf_file_section_buffer_init_index(struct drgn_elf_file_section_buffer *buffer,
struct drgn_elf_file *file,
enum drgn_section_index scn)
{
drgn_elf_file_section_buffer_init(buffer, file, file->scns[scn],
file->scn_data[scn]);
}
/** @} */
#endif /* DRGN_ELF_FILE_H */