tursodatabase/turso · error · SystemExit

{path} has no .dynsym section

Error message

{path} has no .dynsym section

What it means

After scanning the ELF section header table, the script falls back from a section literally named '.dynsym' to any section of type SHT_DYNSYM (11). If neither exists, the binary has no dynamic symbol table, so there are no exported dynamic symbols to check and the script exits with this message.

Source

Thrown at bindings/dotnet/scripts/check_elf_dynsym_exports.py:142

    raise SystemExit(f"{path} has unsupported ELF class {elf_class}")


def find_dynsym(data: bytes, layout: dict, path: Path):
    string_header = section_header(data, layout, layout["string_table_index"])
    names = slice_bytes(data, string_header[OFFSET], string_header[SIZE])
    named = None
    typed = None
    for index in range(layout["section_count"]):
        header = section_header(data, layout, index)
        name = names[header[NAME] :].split(b"\x00", 1)[0]
        if name == b".dynsym":
            named = header
            break
        if typed is None and header[TYPE] == 11:
            typed = header
    dynsym = named or typed
    if dynsym is None:
        raise SystemExit(f"{path} has no .dynsym section")
    return dynsym


def names_from_dynsym(data: bytes, layout: dict, dynsym) -> set[str]:
    strings = section_header(data, layout, dynsym[LINK])
    string_table = slice_bytes(data, strings[OFFSET], strings[SIZE])
    entry_size = dynsym[ENTRY_SIZE] or struct.calcsize(layout["symbol_format"])
    names: set[str] = set()
    for index in range(dynsym[SIZE] // entry_size):
        offset = dynsym[OFFSET] + index * entry_size
        symbol = struct.unpack_from(layout["symbol_format"], data, offset)
        raw = string_table[symbol[0] :].split(b"\x00", 1)[0]
        name = raw.decode("utf-8", "replace")
        if name:
            names.add(name)
    return names

View on GitHub (pinned to 492c4a71cd)

Solutions

  1. Confirm the target is a shared object with exports: `readelf -S <path> | grep dynsym`.
  2. Rebuild with dynamic symbols retained (don't strip .dynsym; ensure the crate/library produces a cdylib/shared artifact).
  3. Point the script at the correct .so file in the build output.
  4. If the platform legitimately has no dynsym, skip or relax the check in CI.

Example fix

// before
python check_elf_dynsym_exports.py ./target/release/tursodb
// after
python check_elf_dynsym_exports.py ./target/release/libturso_dotnet.so
Defensive patterns

Strategy: validation

Validate before calling

import subprocess
def has_dynsym(path: str) -> bool:
    out = subprocess.run(["readelf", "-S", path], capture_output=True, text=True)
    return ".dynsym" in out.stdout

Prevention

When it happens

Trigger: Calling find_dynsym (via dynsym_names) on an ELF that was stripped of its dynamic symbol table, statically linked without exports, or built as a non-shared object with no dynsym section.

Common situations: Checking an executable or static library instead of a shared .so; a release build configured to strip dynamic exports; wrong artifact selected in packaging CI.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


AI-assisted analysis of tursodatabase/turso@492c4a71cd (2026-09-13). Data as JSON: /api/errors/89fceb002cbf5202. Report an issue: GitHub.