libdrgn: use strswitch for ELF section names

Move the definitions of the section names to a Python script,
gen_elf_sections.py, and use that to generate the enum definitions and a
lookup function. This is preparation for checking for section names with
the .dwo suffix in the future.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
This commit is contained in:
Omar Sandoval 2023-02-08 13:22:54 -08:00
parent 93cd8ee0b3
commit 02e344a7dd
5 changed files with 155 additions and 60 deletions

View File

@ -26,7 +26,9 @@ STRSWITCH_INCS = drgn_program_parse_vmcoreinfo.inc \
BUILT_SOURCES = $(ARCH_DEFS_INCS) \
$(STRSWITCH_INCS) \
c_keywords.inc \
drgn.h
drgn.h \
drgn_section_name_to_index.inc \
elf_sections.h
noinst_LTLIBRARIES = libdrgnimpl.la
@ -47,12 +49,14 @@ libdrgnimpl_la_SOURCES = $(ARCH_DEFS_PYS:_defs.py=.c) \
cityhash.h \
debug_info.c \
debug_info.h \
drgn_section_name_to_index.inc \
dwarf_constants.c \
dwarf_constants.h \
dwarf_info.c \
dwarf_info.h \
elf_file.c \
elf_file.h \
elf_sections.h \
error.c \
error.h \
hash_table.c \
@ -131,6 +135,12 @@ drgn.h: drgn.h.in configure.ac
-e 's/@DRGN_VERSION_PATCH@/$(word 3,$(subst ., ,@PACKAGE_VERSION@))/g' \
$< > $@
drgn_section_name_to_index.inc: build-aux/gen_elf_sections.py build-aux/gen_strswitch.py build-aux/codegen_utils.py
$(AM_V_GEN)$(PYTHON) $< | $(PYTHON) $(word 2, $^) -o $@ -
elf_sections.h: build-aux/gen_elf_sections.py build-aux/codegen_utils.py
$(AM_V_GEN)$(PYTHON) $< -H > $@
lib_LTLIBRARIES = libdrgn.la
libdrgn_la_SOURCES =
@ -191,6 +201,7 @@ EXTRA_DIST = $(ARCH_DEFS_PYS) \
build-aux/gen_arch_inc_strswitch.py \
build-aux/gen_c_keywords_inc_strswitch.py \
build-aux/gen_constants.py \
build-aux/gen_elf_sections.py \
build-aux/gen_strswitch.py \
drgn.h.in

View File

@ -4,4 +4,5 @@
!/gen_arch_inc_strswitch.py
!/gen_c_keywords_inc_strswitch.py
!/gen_constants.py
!/gen_elf_sections.py
!/gen_strswitch.py

View File

@ -0,0 +1,136 @@
#!/usr/bin/env python3
# Copyright (c) Meta Platforms, Inc. and affiliates.
# SPDX-License-Identifier: LGPL-2.1-or-later
import argparse
import itertools
import sys
from typing import TextIO
from codegen_utils import c_string_literal
DWARF_INDEX_SECTIONS = (
".debug_info",
".debug_types",
".debug_abbrev",
".debug_str",
".debug_str_offsets",
".debug_line",
".debug_line_str",
)
CACHED_SECTIONS = (
".debug_addr",
".debug_frame",
".eh_frame",
".orc_unwind_ip",
".orc_unwind",
".debug_loc",
".debug_loclists",
)
UNCACHED_SECTIONS = (
".text",
".got",
)
def section_enumerator_name(section_name: str) -> str:
return "DRGN_SCN_" + section_name.lstrip(".").upper()
def gen_elf_sections_h(out_file: TextIO) -> None:
out_file.write(
"""\
/* Generated by libdrgn/build-aux/gen_elf_sections.py -H. */
#ifndef DRGN_ELF_SECTIONS_H
#define DRGN_ELF_SECTIONS_H
/**
* Identifiers for important ELF sections so that they can be referenced by
* index rather than name.
*/
enum drgn_section_index {
"""
)
for section_name in DWARF_INDEX_SECTIONS:
out_file.write(f"\t{section_enumerator_name(section_name)},\n")
out_file.write(
"""\
/** Indices less than this are cached when the module is loaded. */
DRGN_SECTION_INDEX_NUM_PRECACHE,
"""
)
for i, section_name in enumerate(CACHED_SECTIONS):
if i == 0:
out_file.write(
f"\t{section_enumerator_name(section_name)} = DRGN_SECTION_INDEX_NUM_PRECACHE,\n"
)
else:
out_file.write(f"\t{section_enumerator_name(section_name)},\n")
out_file.write(
"""\
/** Indices less than this may have their data cached. */
DRGN_SECTION_INDEX_NUM_DATA,
"""
)
for i, section_name in enumerate(UNCACHED_SECTIONS):
if i == 0:
out_file.write(
f"\t{section_enumerator_name(section_name)} = DRGN_SECTION_INDEX_NUM_DATA,\n"
)
else:
out_file.write(f"\t{section_enumerator_name(section_name)},\n")
out_file.write(
"""\
/** Number of section indices. */
DRGN_SECTION_INDEX_NUM
};
#endif /* DRGN_ELF_SECTIONS_H */
"""
)
def gen_drgn_section_name_to_index_inc_strswitch(out_file: TextIO) -> None:
out_file.write("/* Generated by libdrgn/build-aux/gen_elf_sections.py. */\n")
out_file.write(
"""\
static enum drgn_section_index drgn_section_name_to_index(const char *name)
{
@strswitch (name)@
"""
)
for section_name in itertools.chain(
DWARF_INDEX_SECTIONS, CACHED_SECTIONS, UNCACHED_SECTIONS
):
out_file.write(f"\t@case {c_string_literal(section_name)}@\n")
out_file.write(f"\t\treturn {section_enumerator_name(section_name)};\n")
out_file.write(
"""\
@default@
return DRGN_SECTION_INDEX_NUM;
@endswitch@
}
"""
)
def main() -> None:
parser = argparse.ArgumentParser()
parser.add_argument(
"--header", "-H", action="store_true", help="generate header file"
)
args = parser.parse_args()
if args.header:
gen_elf_sections_h(sys.stdout)
else:
gen_drgn_section_name_to_index_inc_strswitch(sys.stdout)
if __name__ == "__main__":
main()

View File

@ -23,24 +23,7 @@ struct drgn_error *read_elf_section(Elf_Scn *scn, Elf_Data **ret)
return NULL;
}
static const char * const drgn_section_index_names[] = {
[DRGN_SCN_DEBUG_INFO] = ".debug_info",
[DRGN_SCN_DEBUG_TYPES] = ".debug_types",
[DRGN_SCN_DEBUG_ABBREV] = ".debug_abbrev",
[DRGN_SCN_DEBUG_STR] = ".debug_str",
[DRGN_SCN_DEBUG_STR_OFFSETS] = ".debug_str_offsets",
[DRGN_SCN_DEBUG_LINE] = ".debug_line",
[DRGN_SCN_DEBUG_LINE_STR] = ".debug_line_str",
[DRGN_SCN_DEBUG_ADDR] = ".debug_addr",
[DRGN_SCN_DEBUG_FRAME] = ".debug_frame",
[DRGN_SCN_EH_FRAME] = ".eh_frame",
[DRGN_SCN_ORC_UNWIND_IP] = ".orc_unwind_ip",
[DRGN_SCN_ORC_UNWIND] = ".orc_unwind",
[DRGN_SCN_DEBUG_LOC] = ".debug_loc",
[DRGN_SCN_DEBUG_LOCLISTS] = ".debug_loclists",
[DRGN_SCN_TEXT] = ".text",
[DRGN_SCN_GOT] = ".got",
};
#include "drgn_section_name_to_index.inc"
struct drgn_error *drgn_elf_file_create(struct drgn_module *module,
const char *path, Elf *elf,
@ -78,13 +61,10 @@ struct drgn_error *drgn_elf_file_create(struct drgn_module *module,
err = drgn_error_libelf();
goto err;
}
for (size_t i = 0; i < DRGN_SECTION_INDEX_NUM; i++) {
if (!file->scns[i] &&
strcmp(scnname, drgn_section_index_names[i]) == 0) {
file->scns[i] = scn;
break;
}
}
enum drgn_section_index index =
drgn_section_name_to_index(scnname);
if (index < DRGN_SECTION_INDEX_NUM && !file->scns[index])
file->scns[index] = scn;
}
*ret = file;
return NULL;

View File

@ -16,6 +16,7 @@
#include <libelf.h>
#include "binary_buffer.h"
#include "elf_sections.h" // IWYU pragma: export
#include "platform.h"
struct drgn_module;
@ -39,40 +40,6 @@ struct drgn_module;
*/
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. */