Ghidra Extension Points and ServiceProvider API: Complete Implementation Guide

Ghidra extension points are marker interfaces discovered at runtime through suffix-based manifest files, while the ServiceProvider API enables loose coupling between plugins by allowing dynamic lookup of shared services.

The NationalSecurityAgency/ghidra repository implements a sophisticated plugin architecture that centers on two core abstractions: extension points for automatic class discovery and service providers for dependency injection. Understanding how ghidra.util.classfinder.ExtensionPoint and ghidra.framework.plugintool.ServiceProvider interact allows developers to build modular extensions that integrate seamlessly with Ghidra's reverse engineering framework.

Understanding Ghidra Extension Points

Extension points form the backbone of Ghidra's modularity, allowing third-party code to be discovered and loaded without explicit registration in a central registry.

The ExtensionPoint Marker Interface

At the core of this system is ghidra.util.classfinder.ExtensionPoint, a marker interface located in Ghidra/Framework/Generic/src/main/java/ghidra/util/classfinder/ExtensionPoint.java. Any class wishing to participate in automatic discovery must implement this interface, but implementation alone is insufficient for loading.

The critical requirement is the suffix rule: Ghidra's ClassSearcher only loads classes whose simple names end with suffixes declared in data/ExtensionPoint.manifest files. For example, classes ending in "Initializer", "Provider", or "Factory" are loaded only if those suffixes appear in a manifest file within the module's data/ directory.

The Discovery Mechanism

Discovery occurs at startup through ClassSearcher (Ghidra/Framework/Generic/src/main/java/ghidra/util/classfinder/ClassSearcher.java), which performs three operations:

  1. Gather suffixes from every module's data/ExtensionPoint.manifest file (e.g., Ghidra/Framework/Generic/data/ExtensionPoint.manifest)
  2. Scan the classpath for classes ending with those suffixes
  3. Instantiate valid classes via their no-arg constructor and sort them by priority

Common extension point interfaces in the codebase include:

Controlling Loading with Annotations

The @ExtensionPointProperties annotation (Ghidra/Framework/Generic/src/main/java/ghidra/util/classfinder/ExtensionPointProperties.java) provides two key controls:

  • Priority: Higher integer values load first (useful when order matters)
  • Exclusion: Set exclude=true to prevent automatic discovery while keeping the interface implementation
import ghidra.util.classfinder.ExtensionPointProperties;

@ExtensionPointProperties(priority = 100)
public class HighPriorityProvider implements SomeExtensionPoint {
    // This loads before providers with lower priority values
}

Implementing Extension Points in Your Plugin

To create a discoverable extension, you must define the interface, declare the suffix in a manifest, and implement the contract.

Step 1: Define the Extension Point Interface

Create an interface extending ExtensionPoint:

package com.example.ghidra.extensions;

import ghidra.util.classfinder.ExtensionPoint;

public interface AnalysisReporter extends ExtensionPoint {
    void reportFinding(String address, String details);
}

Step 2: Register the Suffix

Create data/ExtensionPoint.manifest in your extension's root directory containing:


Reporter

Step 3: Implement and Deploy

Implement the interface with a class whose name ends in the registered suffix:

package com.example.ghidra.extensions.impl;

import com.example.ghidra.extensions.AnalysisReporter;

public class ConsoleAnalysisReporter implements AnalysisReporter {
    @Override
    public void reportFinding(String address, String details) {
        System.out.printf("[Analysis] %s: %s%n", address, details);
    }
}

When Ghidra starts, ClassSearcher automatically instantiates ConsoleAnalysisReporter because its name ends with "Reporter" and it implements ExtensionPoint.

Using the ServiceProvider API

While extension points enable discovery, the ServiceProvider API enables runtime collaboration between plugins through dependency injection.

Core ServiceProvider Interfaces

The service provider infrastructure resides in Ghidra/Framework/Utility/src/main/java/ghidra/framework/plugintool/ and consists of three primary components:

  • ServiceProvider – The contract defining getService(Class<T>) for service retrieval
  • ServiceProviderStub – A minimal implementation returning null for all services, useful in unit tests
  • ServiceProviderDecorator – Wraps existing providers to add or override services without modifying the original

Accessing Services in Plugins

Plugins receive a ServiceProvider through the PluginTool instance. In Ghidra/Framework/Utility/src/main/java/ghidra/framework/plugintool/Plugin.java, which implements ExtensionPoint, the standard pattern retrieves services in the constructor:

import ghidra.framework.plugintool.Plugin;
import ghidra.framework.plugintool.PluginTool;
import ghidra.framework.plugintool.ServiceProvider;
import ghidra.app.services.GraphService;

public class MyAnalysisPlugin extends Plugin {
    private final GraphService graphService;
    
    public MyAnalysisPlugin(PluginTool tool) {
        super(tool);
        ServiceProvider services = tool.getServiceProvider();
        this.graphService = services.getService(GraphService.class);
    }
}

Decorating and Extending Service Providers

To expose your own services to other plugins, use ServiceProviderDecorator (ServiceProviderDecorator.java):

import ghidra.framework.plugintool.ServiceProvider;
import ghidra.framework.plugintool.ServiceProviderDecorator;

ServiceProvider original = tool.getServiceProvider();
ServiceProvider enhanced = ServiceProviderDecorator.decorate(original)
    .addService(MyCustomService.class, new MyCustomServiceImpl())
    .getProvider();
tool.setServiceProvider(enhanced);

This pattern allows plugins to layer capabilities without requiring other plugins to import your implementation classes directly.

Complete Integration Example

The following example demonstrates defining an extension point, implementing it, and consuming it through the ServiceProvider API:

// Extension point definition
package example;
import ghidra.util.classfinder.ExtensionPoint;

public interface LogFormatter extends ExtensionPoint {
    String format(String message);
}

// Implementation (discovered automatically if "Formatter" is in ExtensionPoint.manifest)
package example.impl;
import example.LogFormatter;

public class TimestampLogFormatter implements LogFormatter {
    @Override
    public String format(String message) {
        return String.format("[%tF %<tT] %s", System.currentTimeMillis(), message);
    }
}

// Consumer using ServiceProvider to access the extension
package example.client;
import ghidra.framework.plugintool.ServiceProvider;
import ghidra.util.classfinder.ClassSearcher;
import example.LogFormatter;
import java.util.List;

public class LogClient {
    private final ServiceProvider provider;
    
    public LogClient(ServiceProvider provider) {
        this.provider = provider;
    }
    
    public void logAllServices() {
        // Direct discovery via ClassSearcher
        List<LogFormatter> formatters = ClassSearcher.getInstances(LogFormatter.class);
        
        for (LogFormatter formatter : formatters) {
            System.out.println(formatter.format("System initialized"));
        }
    }
}

Note that while ClassSearcher provides direct access to extension point implementations, exposing them through ServiceProvider enables other plugins to retrieve them via the standard service lookup mechanism.

Summary

  • Extension points require implementing ghidra.util.classfinder.ExtensionPoint and following the suffix naming convention defined in data/ExtensionPoint.manifest files for automatic discovery by ClassSearcher.
  • Discovery order can be controlled via the @ExtensionPointProperties annotation using priority values or exclusion flags.
  • ServiceProvider (ghidra.framework.plugintool.ServiceProvider) decouples plugins by allowing runtime lookup of services rather than compile-time dependencies.
  • ServiceProviderDecorator enables extending service capabilities without modifying existing provider implementations, supporting layered plugin architectures.
  • PluginTool serves as the primary source of ServiceProvider instances for plugins, retrieved via getServiceProvider() in the plugin constructor.

Frequently Asked Questions

What is the difference between an ExtensionPoint and a ServiceProvider?

An ExtensionPoint is a marker interface for classes that Ghidra discovers and instantiates automatically at startup based on naming suffixes in manifest files. A ServiceProvider is a runtime lookup mechanism that allows plugins to retrieve shared objects (services) dynamically using getService(Class<T>). Extension points define what can be extended; ServiceProvider defines how plugins share functionality.

How does Ghidra automatically discover my extension point implementation?

Ghidra's ClassSearcher (Ghidra/Framework/Generic/src/main/java/ghidra/util/classfinder/ClassSearcher.java) scans the classpath at startup, reading every module's data/ExtensionPoint.manifest file to collect valid suffixes. It then instantiates any class whose simple name ends with a registered suffix and which implements the ExtensionPoint marker interface. Simply implementing the interface is insufficient; the suffix must be declared in a manifest file.

Can I prevent my extension point from being loaded automatically?

Yes. Add the @ExtensionPointProperties annotation with exclude=true to your class declaration. Located in Ghidra/Framework/Generic/src/main/java/ghidra/util/classfinder/ExtensionPointProperties.java, this annotation tells ClassSearcher to skip the class during discovery, allowing you to instantiate it manually or control its lifecycle programmatically.

How do I access services from a class that is not a Plugin?

If your class does not extend Plugin but needs access to services, obtain a ServiceProvider instance from an existing plugin or tool context, or use ServiceProviderStub for testing scenarios. For standalone utilities, you can also use ClassSearcher.getInstances(ServiceClass.class) to discover implementations directly, though this bypasses the service lifecycle management that PluginTool provides.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →