drgn/libdrgn/elf_file.h

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

187 lines
4.6 KiB
C
Raw Normal View History

// 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 "binary_buffer.h"
#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);
/**
* Identifiers for important ELF sections so that they can be referenced by
* index rather than name.
*/
enum drgn_section_index {
DRGN_SCN_DEBUG_INFO,
DRGN_SCN_DEBUG_TYPES,
DRGN_SCN_DEBUG_ABBREV,
DRGN_SCN_DEBUG_STR,
DRGN_SCN_DEBUG_STR_OFFSETS,
DRGN_SCN_DEBUG_LINE,
DRGN_SCN_DEBUG_LINE_STR,
/** Indices less than this are cached when the module is loaded. */
DRGN_SECTION_INDEX_NUM_PRECACHE,
DRGN_SCN_DEBUG_ADDR = DRGN_SECTION_INDEX_NUM_PRECACHE,
DRGN_SCN_DEBUG_FRAME,
DRGN_SCN_EH_FRAME,
DRGN_SCN_ORC_UNWIND_IP,
DRGN_SCN_ORC_UNWIND,
DRGN_SCN_DEBUG_LOC,
DRGN_SCN_DEBUG_LOCLISTS,
/** Indices less than this may have their data cached. */
DRGN_SECTION_INDEX_NUM_DATA,
DRGN_SCN_TEXT = DRGN_SECTION_INDEX_NUM_DATA,
DRGN_SCN_GOT,
/** Number of section indices. */
DRGN_SECTION_INDEX_NUM,
};
/** 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);
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 */