# Ghidra Variable APIs: Storage vs Decompiler SSA

## The Two Variable Systems in Ghidra

Ghidra maintains TWO separate variable naming systems that serve different purposes. Understanding the difference is critical for implementing variable renaming correctly.

## System 1: Storage-Based Variables

### What Are They?

Variables defined by their **physical storage location** (stack offset or register).

### How to Access

```java
Function func = ...;

// Get parameters
for (Parameter param : func.getParameters()) {
    String name = param.getName();        // e.g., "param_1", "param_2"
    String type = param.getDataType();    // e.g., "double"
    String storage = param.getStorage();  // e.g., "Stack[0xc]:8"
}

// Get local variables
for (Variable local : func.getLocalVariables()) {
    String name = local.getName();        // e.g., "local_c", "local_10"
    String type = local.getDataType();    // e.g., "undefined4"
    String storage = local.getStorage();  // e.g., "Stack[-0xc]:4"
}
```

### Example Names

- `param_1`, `param_2`, `param_3` - Parameters
- `local_c`, `local_10`, `local_14` - Stack locals at specific offsets
- `__return_storage_ptr__` - Return value storage

### How to Rename

```java
param.setName("newName", SourceType.USER_DEFINED);
local.setName("newName", SourceType.USER_DEFINED);
```

### Where They Appear

- Function signature metadata
- Symbol tree in Ghidra
- `get_function_variables` MCP tool output
- **NOT in decompiled code** (decompiler uses SSA variables instead)

### Purpose

- Track physical memory/register allocation
- Define function calling convention
- Map assembly to high-level representation

## System 2: Decompiler SSA Variables

### What Are They?

Variables generated by **Static Single Assignment (SSA)** data flow analysis during decompilation.

### How to Access

```java
DecompInterface decomp = new DecompInterface();
decomp.openProgram(program);

DecompileResults result = decomp.decompileFunction(func, timeout, monitor);
HighFunction highFunction = result.getHighFunction();
LocalSymbolMap localSymbolMap = highFunction.getLocalSymbolMap();

Iterator<HighSymbol> symbols = localSymbolMap.getSymbols();
while (symbols.hasNext()) {
    HighSymbol symbol = symbols.next();
    String name = symbol.getName();           // e.g., "dVar12", "uVar3"
    DataType type = symbol.getDataType();     // e.g., "double", "uint"
    HighVariable var = symbol.getHighVariable();
}
```

### Example Names

SSA variables use **Hungarian notation** with type prefix:
- `dVar12`, `dVar13` - Double precision floats
- `iVar6` - Signed integers
- `uVar2`, `uVar3` - Unsigned integers
- `bVar1` - Bytes
- `lVar20`, `lVar21` - Longs
- `pfVar7`, `pfVar8` - Pointers to float
- `auVar16[16]` - Undefined array (SIMD registers)

### How to Rename

```java
HighFunctionDBUtil.updateDBVariable(
    highSymbol,
    "newName",
    null,  // dataType (null = keep existing)
    SourceType.USER_DEFINED
);
```

### Where They Appear

- **Decompiled code output** (this is what users see!)
- Decompiler window in Ghidra
- `get_decompiled_code` MCP tool output

### Purpose

- Represent data flow in decompiled pseudocode
- One variable per assignment (SSA property)
- Enable compiler-style optimizations
- Present human-readable code

## The Critical Difference

### Storage Variables

```
Stack[-0xc]:8  ←→  local_c (undefined8)
```

This says: "There's an 8-byte value at stack offset -0xc that we'll call `local_c`"

### SSA Variables (Generated from Storage)

```
local_c  →  Decompiler Analysis  →  dVar12, dVar13, dVar14 (multiple SSA vars)
```

The decompiler reads the value at `Stack[-0xc]`, performs SSA data flow analysis, and discovers that this storage location is used for THREE different logical values at different points in the function. So it creates three separate SSA variables: `dVar12`, `dVar13`, `dVar14`.

## Example: ComputePowerDouble Function

### Storage View (func.getLocalVariables)

```json
{
  "locals": [
    {"name": "local_c", "type": "undefined8", "storage": "Stack[-0xc]:8"},
    {"name": "local_10", "type": "undefined4", "storage": "Stack[-0x10]:4"},
    {"name": "local_14", "type": "undefined4", "storage": "Stack[-0x14]:4"}
  ]
}
```

### Decompiler SSA View (LocalSymbolMap.getSymbols)

```c
double dVar12;   // Derived from local_c storage
double dVar13;   // Derived from local_c storage (reused)
double dVar14;   // Derived from parameter storage
double dVar15;   // Derived from parameter storage (reused)
uint uVar2;      // Derived from local_10 storage
uint uVar3;      // Derived from local_14 storage
byte bVar1;      // Temporary value (no storage mapping)
```

**Notice**: One storage variable (`local_c`) can produce MULTIPLE SSA variables (`dVar12`, `dVar13`) because the compiler reused that stack location for different logical values.

## What Users See vs What Gets Renamed

### User Views Decompiled Code

```c
double dVar12;
double dVar13;
uint uVar2;

dVar12 = (double)(ulonglong)((uint)in_stack_00000008 >> 0xc);
dVar13 = (double)(...);
uVar3 = ((uint)in_stack_00000008 >> 0xc & 0xff) + 1 & 0x1fe;
```

**User wants to rename**: `dVar12` → `scaledMantissa`, `dVar13` → `exponentValue`

### Old Batch Method Renamed Wrong Variables

```java
// This renames local_c, local_10, local_14 (storage variables)
for (Variable local : func.getLocalVariables()) {
    local.setName(newName, SourceType.USER_DEFINED);
}
```

**Result**: Storage variables renamed, but decompiled code UNCHANGED (still shows `dVar12`, `dVar13`)

### Correct Method Renames SSA Variables

```java
// This renames dVar12, dVar13, uVar2 (SSA variables)
Iterator<HighSymbol> symbols = localSymbolMap.getSymbols();
while (symbols.hasNext()) {
    HighSymbol symbol = symbols.next();
    HighFunctionDBUtil.updateDBVariable(symbol, newName, null, SourceType.USER_DEFINED);
}
```

**Result**: Decompiled code UPDATED with new names ✅

## Non-Renameable Variables

Some SSA variables cannot be renamed because they represent implicit compiler behavior:

### Register Inputs/Outputs

```c
undefined8 in_XMM1_Qa;      // Implicit SSE register input
float10 *extraout_EAX;      // Implicit EAX output from called function
ulonglong in_XMM2_Qa;       // Implicit XMM2 input
float10 *in_stack_00000008; // Implicit stack parameter
```

These are NOT in LocalSymbolMap - they're created by the decompiler to represent calling convention details that don't have explicit storage.

### Undefined Arrays

```c
undefined1 auVar16 [16];    // Undefined 16-byte SIMD register
```

These represent SIMD registers whose exact type isn't known.

### Why Can't They Be Renamed?

They're **implicit/synthetic** - not actual function variables. They represent:
- Calling convention details (implicit register parameters)
- Return values from function calls (extraout_*)
- Compiler-generated temporaries (undefined arrays)

## Summary Table

| Aspect | Storage Variables | SSA Variables |
|--------|------------------|---------------|
| **Access API** | `func.getLocalVariables()` | `LocalSymbolMap.getSymbols()` |
| **Example Names** | `local_c`, `param_1` | `dVar12`, `uVar3`, `bVar1` |
| **Rename API** | `variable.setName()` | `HighFunctionDBUtil.updateDBVariable()` |
| **Appears In** | Symbol tree, metadata | **Decompiled code** |
| **Count** | ~5-10 per function | ~20-50 per function |
| **Purpose** | Track storage allocation | Present readable pseudocode |
| **User Cares?** | No (internal detail) | **YES** (what they see!) |

## Conclusion

**To rename variables that appear in decompiled code, you MUST use the HighFunction/LocalSymbolMap API.**

Storage variable renaming only affects internal metadata that users never see. The batch rename method needs to be fixed to use the correct API.
