NationalSecurityAgency/ghidra · error · RuntimeError

No register mapper

Error message

No register mapper

What it means

Raised by Extra.require_rm in the Ghidra LLDB agent when register_mapper has not been set on the trace's Extra object. The register mapper translates register names and byte values between Ghidra and LLDB; without it, register read/write trace operations cannot proceed. RuntimeError signals a missing precondition — the mapper must be constructed (DefaultRegisterMapper with valid byte_order) and assigned before any register operation.

Source

Thrown at Ghidra/Debug/Debugger-agent-lldb/src/main/py/src/ghidralldb/commands.py:87

MODULE_PATTERN = MODULES_PATTERN + MODULE_KEY_PATTERN
SECTIONS_ADD_PATTERN = '.Sections'
SECTION_KEY_PATTERN = '[{secname}]'
SECTION_ADD_PATTERN = SECTIONS_ADD_PATTERN + SECTION_KEY_PATTERN


class Extra(object):
    def __init__(self) -> None:
        self.memory_mapper: Optional[arch.DefaultMemoryMapper] = None
        self.register_mapper: Optional[arch.DefaultRegisterMapper] = None

    def require_mm(self) -> arch.DefaultMemoryMapper:
        if self.memory_mapper is None:
            raise RuntimeError("No memory mapper")
        return self.memory_mapper

    def require_rm(self) -> arch.DefaultRegisterMapper:
        if self.register_mapper is None:
            raise RuntimeError("No register mapper")
        return self.register_mapper


class State(object):

    def __init__(self) -> None:
        self.reset_client()

    def require_client(self) -> Client:
        if self.client is None:
            raise RuntimeError("Not connected")
        return self.client

    def require_no_client(self) -> None:
        if self.client is not None:
            raise RuntimeError("Already connected")

    def reset_client(self) -> None:

View on GitHub (pinned to d5f144c24d)

Solutions

  1. Ensure the activate/environment step assigns trace.extra.register_mapper (with a validated byte_order) before any register method runs.
  2. Lazily initialize register_mapper in require_rm using the detected endianness.
  3. Order commands so register operations occur only after target launch and arch/endianness detection.
  4. Verify byte_order normalization (see error 191) so mapper construction does not silently fail.

Example fix

// before
rv = frame.trace.extra.require_rm().map_value_back(proc, name, value)
// after
extra = frame.trace.extra
if extra.register_mapper is None:
    extra.register_mapper = arch.DefaultRegisterMapper(normalized_byte_order)
rv = extra.require_rm().map_value_back(proc, name, value)
Defensive patterns

Strategy: validation

Validate before calling

extra = trace.extra
if extra.register_mapper is None:
    extra.register_mapper = arch.DefaultRegisterMapper(normalized_byte_order)
rv = extra.require_rm().map_value_back(proc, name, value)

Type guard

def register_mapper_ready(extra) -> bool:
    return extra.register_mapper is not None

Try / catch

try:
    rm = trace.extra.require_rm()
except RuntimeError:
    trace.extra.register_mapper = arch.DefaultRegisterMapper(detected_endianness())
    rm = trace.extra.require_rm()

Prevention

When it happens

Trigger: Calling trace.extra.require_rm() before the agent initialized register_mapper — e.g. a register method fired during startup before the register mapper was assigned, or arch/endianness detection failed and the assignment was skipped. Reached by methods that read/translate register values.

Common situations: Trace-activate step that sets register_mapper did not complete (target not launched, arch detection failed); endianness detection returned an invalid value causing mapper construction to be skipped; ordering bug where a register method runs before activate.

Related errors


AI-assisted analysis of NationalSecurityAgency/ghidra@d5f144c24d (2026-08-14). Data as JSON: /api/errors/cab3dbda9bdab6b6. Report an issue: GitHub.