Skip to main content

Program Model

The Program interface is the central abstraction for representing executable binaries in Ghidra. It extends DomainObject and provides access to all aspects of a program’s structure.
// From ghidra/program/model/listing/Program.java:40-53
public interface Program extends DataTypeManagerDomainObject, ProgramArchitecture {
    Listing getListing();
    Memory getMemory();
    SymbolTable getSymbolTable();
    FunctionManager getFunctionManager();
    ReferenceManager getReferenceManager();
    BookmarkManager getBookmarkManager();
    EquateTable getEquateTable();
    ExternalManager getExternalManager();
    RelocationTable getRelocationTable();
    ProgramBasedDataTypeManager getDataTypeManager();
}

Program Components

A program is divided into several major subsystems, each managed by a dedicated interface.

Memory

The memory subsystem manages the program’s address space and byte storage.
// From ghidra/program/model/mem/Memory.java:30-79
public interface Memory extends AddressSetView {
    Program getProgram();
    
    // Address set queries
    AddressSetView getLoadedAndInitializedAddressSet();
    AddressSetView getAllInitializedAddressSet();
    AddressSetView getExecuteSet();
    
    // Block management
    MemoryBlock[] getBlocks();
    MemoryBlock getBlock(Address addr);
    MemoryBlock getBlock(String blockName);
    
    // Byte access
    byte getByte(Address addr);
    void setByte(Address addr, byte value);
    int getBytes(Address addr, byte[] dest);
    void setBytes(Address addr, byte[] source);
}

Memory Blocks

Memory is organized into contiguous blocks:
public interface MemoryBlock extends Comparable<MemoryBlock> {
    String getName();
    Address getStart();
    Address getEnd();
    long getSize();
    
    boolean isRead();
    boolean isWrite();
    boolean isExecute();
    boolean isVolatile();
    
    boolean isInitialized();
    boolean isMapped();
    boolean isLoaded();
    boolean isOverlay();
}
Block Types:

Initialized

Contains specific data loaded from the binary file

Uninitialized

Defines a region but content is unknown (e.g., BSS)

Byte-Mapped

Maps to another region with byte-level mapping

Bit-Mapped

Maps to bits in another region (1 byte = 1 bit)
From ghidra/program/model/mem/Memory.java:43-56

Creating Memory Blocks

// Initialized block from byte array
MemoryBlock block = memory.createInitializedBlock(
    ".text",              // Block name
    addr(0x401000),       // Start address
    bytes,                // Initial data
    false                 // Overlay?
);

// Uninitialized block
MemoryBlock bss = memory.createUninitializedBlock(
    ".bss",
    addr(0x500000),
    0x1000,               // Size
    false
);

// Byte-mapped block (mirror another region)
MemoryBlock mapped = memory.createByteMappedBlock(
    "mirror",
    addr(0x600000),
    addr(0x401000),       // Maps to .text
    0x1000
);
All block operations require exclusive access and should be performed within a transaction.

Overlay Blocks

Overlay address spaces provide alternate contexts for memory:
// Create overlay space
MemoryBlock overlay = memory.createInitializedBlock(
    "overlay_1",
    addr("overlay_1::0x401000"),  // Note address space prefix
    bytes,
    true                           // Overlay = true
);
Use Cases:
  • Multiple executable contexts (RTOS tasks)
  • Paged memory architectures
  • Bank-switched memory
  • Alternate code paths
Overlays have limitations during analysis. References between overlay and base memory may not be discovered automatically.

Address Spaces

Ghidra supports multiple address spaces within a single program.

Address Interface

// From ghidra/program/model/address/Address.java:23-30
public interface Address extends Comparable<Address> {
    AddressSpace getAddressSpace();
    long getOffset();
    
    Address add(long displacement);
    Address subtract(long displacement);
    long subtract(Address addr);
    
    boolean isMemoryAddress();
    boolean isExternalAddress();
}

AddressSpace Types

From ghidra/program/model/address/AddressSpace.java:28-89
public interface AddressSpace extends Comparable<AddressSpace> {
    // Physical memory (loaded into RAM)
    public static final int TYPE_RAM = 1;
    
    // Processor registers
    public static final int TYPE_REGISTER = 4;
    
    // Stack-relative (signed offsets)
    public static final int TYPE_STACK = 5;
    
    // Non-loaded data (file headers, debug sections)
    public static final int TYPE_OTHER = 7;
    
    // External library references
    public static final int TYPE_EXTERNAL = 10;
    
    String getName();
    int getSpaceID();
    int getSize();                    // Address width in bits
    int getAddressableUnitSize();     // Bytes per address unit
}
Common Address Spaces:
SpaceTypeDescription
ramRAMPhysical memory
registerREGISTERCPU registers
stackSTACKStack-relative addressing
EXTERNALEXTERNALExternal symbols
OTHEROTHERNon-loaded data
constCONSTANTAnalysis constants
uniqueUNIQUETemporary values

Address Arithmetic

Address addr = program.getAddressFactory().getAddress("ram:0x401000");

// Add offset
Address next = addr.add(4);           // ram:0x401004

// Subtract addresses
long diff = next.subtract(addr);      // 4

// Address comparison
if (addr.compareTo(next) < 0) {
    // addr comes before next
}
Use AddressSet and AddressRange for efficient representation of address collections:
AddressSet set = new AddressSet();
set.add(new AddressRangeImpl(start, end));
set.add(anotherAddress);

if (set.contains(addr)) {
    // Address is in set
}

Listing

The listing provides access to code units, instructions, and data:
public interface Listing {
    CodeUnit getCodeUnitAt(Address addr);
    CodeUnit getCodeUnitContaining(Address addr);
    CodeUnit getCodeUnitAfter(Address addr);
    CodeUnit getCodeUnitBefore(Address addr);
    
    Instruction getInstructionAt(Address addr);
    Instruction getInstructionContaining(Address addr);
    
    Data getDataAt(Address addr);
    Data getDefinedDataAt(Address addr);
    Data createData(Address addr, DataType dataType);
}

Code Units

Code units are the atomic elements of the listing:
public interface CodeUnit {
    Address getAddress();
    Address getMinAddress();
    Address getMaxAddress();
    int getLength();
    byte[] getBytes();
    
    String getLabel();
    String getComment(int commentType);
    void setComment(int commentType, String comment);
}
Code Unit Types:
  • Instruction - Disassembled processor instruction
  • Data - Defined data with a specific type
  • Undefined - Unanalyzed bytes

Instructions

public interface Instruction extends CodeUnit {
    String getMnemonicString();
    int getNumOperands();
    Object[] getOpObjects(int opIndex);
    Address[] getReferencesFrom();
    FlowType getFlowType();
    boolean isFallthrough();
    Address getFallThrough();
}

Data

public interface Data extends CodeUnit {
    DataType getDataType();
    boolean isDefined();
    int getNumComponents();
    Data getComponent(int index);
    Object getValue();
}

Symbol Table

The symbol table manages labels, functions, and namespaces:
public interface SymbolTable {
    Symbol getPrimarySymbol(Address addr);
    Symbol[] getSymbols(Address addr);
    Symbol getSymbol(String name, Namespace namespace);
    
    Symbol createLabel(Address addr, String name, Namespace namespace, 
                      SourceType source);
    
    SymbolIterator getSymbols(String name);
    SymbolIterator getSymbols(Namespace namespace);
    SymbolIterator getAllSymbols(boolean includeDynamicSymbols);
}

Symbols

public interface Symbol {
    String getName();
    Address getAddress();
    Namespace getParentNamespace();
    SymbolType getSymbolType();
    SourceType getSource();
    boolean isPrimary();
    boolean isDynamic();
    boolean isExternal();
}
Symbol Types:
  • FUNCTION - Function entry point
  • LABEL - Address label
  • NAMESPACE - Namespace container
  • CLASS - Class namespace
  • PARAMETER - Function parameter
  • LOCAL_VAR - Local variable
  • GLOBAL_VAR - Global variable

Namespaces

public interface Namespace {
    String getName();
    String getName(boolean includeNamespacePath);
    Namespace getParentNamespace();
    Symbol getSymbol();
}
Namespaces organize symbols hierarchically:
Global
  └─ MyClass
      ├─ method1
      └─ method2
  └─ AnotherClass
      └─ function

Function Manager

Manages functions and their properties:
public interface FunctionManager {
    Function getFunctionAt(Address entryPoint);
    Function getFunctionContaining(Address addr);
    
    Function createFunction(String name, Address entryPoint, 
                           AddressSetView body, SourceType source);
    
    FunctionIterator getFunctions(boolean forward);
    FunctionIterator getFunctions(AddressSetView asv, boolean forward);
    int getFunctionCount();
}

Functions

public interface Function extends Namespace {
    Address getEntryPoint();
    AddressSetView getBody();
    
    Parameter[] getParameters();
    Parameter getReturn();
    Variable[] getLocalVariables();
    
    String getPrototypeString(boolean includeName, boolean includeReturn);
    void setCustomVariableStorage(boolean hasCustomVariableStorage);
}

Reference Manager

Tracks all memory references and cross-references:
public interface ReferenceManager {
    Reference addMemoryReference(Address fromAddr, Address toAddr, 
                                RefType type, SourceType sourceType, 
                                int opIndex);
    
    Reference[] getReferencesFrom(Address addr);
    Reference[] getReferencesTo(Address addr);
    ReferenceIterator getReferencesTo(Address addr);
    
    void delete(Reference ref);
}
Reference Types:
  • READ - Data read
  • WRITE - Data write
  • UNCONDITIONAL_JUMP - Direct jump
  • CONDITIONAL_JUMP - Conditional branch
  • UNCONDITIONAL_CALL - Function call
  • FALL_THROUGH - Sequential flow
  • EXTERNAL_REF - Reference to external symbol

Data Types

Programs have an associated data type manager:
public interface ProgramBasedDataTypeManager extends DataTypeManager {
    DataType resolve(DataType dataType, DataTypeConflictHandler handler);
    Category getCategory(CategoryPath path);
    DataType getDataType(String dataTypePath);
    void addDataTypeManagerListener(DataTypeManagerChangeListener listener);
}

Built-in Data Types

  • Primitives: byte, word, dword, qword
  • Signed: sbyte, short, int, long
  • Floating: float, double
  • Text: string, unicode
  • Pointers: pointer, pointer32, pointer64

Custom Data Types

// Structure
Structure struct = new StructureDataType("MyStruct", 0);
struct.add(IntegerDataType.dataType, "field1", null);
struct.add(PointerDataType.dataType, "field2", null);

// Array
Array arr = new ArrayDataType(IntegerDataType.dataType, 10, 4);

// Typedef
Typedef td = new TypedefDataType("DWORD", IntegerDataType.dataType);

Program Properties

Programs store metadata in property lists:
Options options = program.getOptions(Program.PROGRAM_INFO);
options.setString("Compiler", "gcc");
options.setString("Executable Format", "ELF");

boolean analyzed = options.getBoolean(Program.ANALYZED_OPTION_NAME, false);
From ghidra/program/model/listing/Program.java:54-64

Language and Architecture

public interface Program extends ProgramArchitecture {
    Language getLanguage();
    CompilerSpec getCompilerSpec();
    int getDefaultPointerSize();
    String getCompiler();
    void setCompiler(String compiler);
}

Language Definition

  • Processor instruction set
  • Register definitions
  • P-code semantics
  • Calling conventions
  • Memory model

Transaction Model

All program modifications must occur within transactions:
// Explicit transaction
int txId = program.startTransaction("Make changes");
try {
    // Modify program
    memory.setByte(addr, (byte)0x90);
    program.endTransaction(txId, true);
} catch (Exception e) {
    program.endTransaction(txId, false);  // Rollback
}

// Try-with-resources
try (Transaction tx = program.openTransaction("Make changes")) {
    memory.setByte(addr, (byte)0x90);
    // Automatically commits on success
}
Forgetting to start a transaction will result in an exception when attempting to modify the program.

Program Events

Programs generate events for changes:
program.addListener(new DomainObjectListener() {
    @Override
    public void domainObjectChanged(DomainObjectChangedEvent ev) {
        for (DomainObjectChangeRecord rec : ev) {
            EventType type = rec.getEventType();
            if (type == ProgramEvent.MEMORY_BLOCK_ADDED) {
                Address start = (Address) rec.getObject();
                // Handle new memory block
            }
        }
    }
});
Common Program Events:
  • MEMORY_BLOCK_ADDED / REMOVED
  • CODE_ADDED / REMOVED
  • FUNCTION_ADDED / REMOVED
  • SYMBOL_ADDED / RENAMED / REMOVED
  • DATA_TYPE_ADDED / CHANGED

Best Practices

  • Create memory blocks before analysis
  • Use meaningful block names
  • Set proper permissions (R/W/X)
  • Consider using overlays for alternate contexts
  • Use descriptive symbol names
  • Organize with namespaces
  • Mark important symbols as primary
  • Document symbol sources
  • Define structures for complex data
  • Share data types via archives
  • Apply types consistently
  • Use categories to organize types
  • Keep transactions focused and small
  • Use descriptive transaction names
  • Always commit or rollback explicitly
  • Avoid long-running transactions

Next Steps

Analysis

Learn about program analysis

Projects

Understand project organization

Architecture

Explore framework architecture

Overview

Return to framework overview

Build docs developers (and LLMs) love