{"record":{"id":"0dde18ac01d39143","repo":"NationalSecurityAgency/ghidra","slug":"expression-expression-does-not-have-an-address","errorCode":null,"errorMessage":"Expression {expression} does not have an address","messagePattern":"Expression (.+?) does not have an address","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"Ghidra/Debug/Debugger-agent-lldb/src/main/py/src/ghidralldb/commands.py","lineNumber":775,"sourceCode":"\n    args = shlex.split(command)\n    if len(args) == 1:\n        expression = args[0]\n        pages = True\n    elif len(args) == 2:\n        expression = args[0]\n        pages = (util.get_eval(args[2]).unsigned != 0)\n    else:\n        raise RuntimeError(\"Usage: ghidra trace putval EXPRESSION [PAGES]\")\n\n    STATE.require_tx()\n    try:\n        value = util.get_eval(expression)\n        address = value.addr\n    except BaseException as e:\n        raise RuntimeError(f\"Could not evaluate {expression}: {e}\")\n    if not address.IsValid():\n        raise RuntimeError(f\"Expression {expression} does not have an address\")\n    start = int(address)\n    end = start + start + value.size\n    return put_bytes(start, end, result, pages)\n\n\ndef putmem_state(address: str, length: str, state: str,\n                 pages: bool = True) -> None:\n    trace = STATE.require_trace()\n    trace.validate_state(state)\n    start, end = eval_range(address, length)\n    if start is None or end is None:\n        return\n    if pages:\n        start, end = quantize_pages(start, end)\n    proc = util.get_process()\n    base, addr = trace.extra.require_mm().map(proc, start)\n    if base != addr.space:\n        trace.create_overlay_space(base, addr.space)","sourceCodeStart":757,"sourceCodeEnd":793,"githubUrl":"https://github.com/NationalSecurityAgency/ghidra/blob/d5f144c24d6bc53c9cbf4448c6d11143e7696206/Ghidra/Debug/Debugger-agent-lldb/src/main/py/src/ghidralldb/commands.py#L757-L793","documentation":"Thrown by ghidra_trace_putval when the evaluated value's SBValue.addr is not valid. putval only makes sense for values that live in memory (their bytes can be copied into the trace); pure registers and compile-time constants have no address, so the command refuses them.","triggerScenarios":"Passing an immediate/constant expression (e.g. 'putval 42'), a register-only value, or an rvalue whose address LLDB cannot materialize. value.addr.IsValid() returns false for these.","commonSituations":"User treats putval as 'record any value' rather than 'record a memory-resident value'; trying to record a register (use putreg instead); passing a literal number.","solutions":["Use a memory-resident expression: a global variable, a dereferenced pointer, or a stack object.","To record registers, use 'ghidra trace putreg' instead of putval.","Take the address explicitly if you meant the storage: 'putval &myvar'."],"exampleFix":"// before\nghidra trace putval 0xdeadbeef\n// after\nghidra trace putval global_buffer","handlingStrategy":"type-guard","validationCode":"from ghidralldb import util\n\ndef has_memory_address(expr: str) -> bool:\n    try:\n        return util.get_eval(expr).addr.IsValid()\n    except BaseException:\n        return False","typeGuard":"def is_memory_resident(value: 'lldb.SBValue') -> bool:\n    return bool(value.addr.IsValid())","tryCatchPattern":"value = util.get_eval(expression)\nif not value.addr.IsValid():\n    # fall back to recording via putreg if it is a register\n    ghidra_trace_putreg(debugger, '<group>', result, internal_dict)","preventionTips":["Use putval only for memory-resident values (globals, dereferenced pointers, stack objects).","Use putreg for registers, not putval.","Take the address explicitly (&var) when you mean the storage."],"tags":["ghidra-trace","expression-eval","memory-address","argument-validation"],"backgroundTag":null,"analyzedSha":"d5f144c24d6bc53c9cbf4448c6d11143e7696206","analyzedAt":"2026-08-14T01:00:57.564Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}