Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ dependencies {
implementation 'org.json:json:20250107'
implementation "com.google.guava:guava:33.2.0-jre"
implementation group: 'com.fifesoft', name: 'rsyntaxtextarea', version: '3.5.2'
implementation('ai.reveng:sdk:3.0.0')
implementation('ai.reveng:sdk:3.82.2')
testImplementation('junit:junit:4.13.1')
testRuntimeOnly("org.junit.vintage:junit-vintage-engine:5.8.2")

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package ai.reveng.toolkit.ghidra.binarysimilarity.ui.aidecompiler;

import ai.reveng.invoker.ApiException;
import ai.reveng.model.AiDecompilationTaskStatus;
import ai.reveng.model.GetAiDecompilationTask;
import ai.reveng.toolkit.ghidra.core.services.api.GhidraRevengService;
import ai.reveng.toolkit.ghidra.core.services.api.TypedApiInterface;
Expand Down Expand Up @@ -207,7 +208,7 @@ public JComponent getComponent() {

public void setDisplayedValuesBasedOnStatus(Function function, GetAiDecompilationTask status) {
this.function = function;
if (status.getStatus().equals("success")) {
if (status.getStatus() == AiDecompilationTaskStatus.SUCCESS) {
setCode(status.getDecompilation());
descriptionArea.setText("<html>%s</html>".formatted(status.getSummary()));

Expand All @@ -219,7 +220,7 @@ public void setDisplayedValuesBasedOnStatus(Function function, GetAiDecompilatio
} else {
predictedNamePanel.setVisible(false);
}
} else if (status.getStatus().equals("error")) {
} else if (status.getStatus() == AiDecompilationTaskStatus.ERROR) {
setCode("");
descriptionArea.setText("Decompilation failed");
predictedNamePanel.setVisible(false);
Expand Down Expand Up @@ -286,21 +287,21 @@ void newStatusForFunction(Function function, GetAiDecompilationTask status) {
setDisplayedValuesBasedOnStatus(function, status)
);
}
if (status.getStatus().equals("success")) {
if (status.getStatus() == AiDecompilationTaskStatus.SUCCESS) {
var logger = tool.getService(ReaiLoggingService.class);
logger.info("AI Decompilation finished for function %s: %s".formatted(function.getName(), status.getDecompilation()));
if (!hasPendingDecompilations()) {
taskMonitorComponent.setVisible(false);
}
} else if (status.getStatus().equals("error")) {
} else if (status.getStatus() == AiDecompilationTaskStatus.ERROR) {
if (!hasPendingDecompilations()) {
taskMonitorComponent.setVisible(false);
}
}
}

private boolean hasPendingDecompilations() {
return cache.values().stream().anyMatch(s -> s.getStatus().equals("pending") || s.getStatus().equals("running") || s.getStatus().equals("queued"));
return cache.values().stream().anyMatch(s -> s.getStatus() == AiDecompilationTaskStatus.PENDING);
}
class AIDecompTask extends Task {

Expand All @@ -317,7 +318,7 @@ public AIDecompTask(PluginTool tool, GhidraRevengService.FunctionWithID function
public void run(TaskMonitor monitor) throws CancelledException {
var fID = functionWithID.functionID();
// Check if there is an existing process already, because the trigger API will fail with 400 if there is
if (service.getApi().pollAIDecompileStatus(fID).getStatus().equals("uninitialised")) {
if (service.getApi().pollAIDecompileStatus(fID).getStatus() == AiDecompilationTaskStatus.UNINITIALISED) {
// Trigger the decompilation
service.getApi().triggerAIDecompilationForFunctionID(fID);
}
Expand All @@ -340,21 +341,19 @@ private void waitForDecomp(TypedApiInterface.FunctionID id, TaskMonitor monitor)
monitor.setMessage("Waiting for AI Decompilation for %s ... Current status: %s".formatted(functionWithID.function().getName(), lastDecompStatus.getStatus()));
monitor.checkCancelled();
switch (newStatus.getStatus()) {
case "pending":
case "uninitialised":
case "queued":
case "running":
case PENDING:
case UNINITIALISED:
try {
// Wait a second before polling again. We don't want to spam the API with requests too often
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
break;
case "success":
case SUCCESS:
monitor.setProgress(monitor.getMaximum());
return;
case "error":
case ERROR:
logger.error("Decompilation failed: %s".formatted(newStatus.getDecompilation()));
return;
default:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -645,7 +645,7 @@ public String decompileFunctionViaAI(FunctionWithID functionWithID, TaskMonitor
// Check if there is an existing process already, because the trigger API will fail with 400 if there is
var fID = functionWithID.functionID;
var function = functionWithID.function;
if (api.pollAIDecompileStatus(fID).getStatus().equals("uninitialised")){
if (api.pollAIDecompileStatus(fID).getStatus() == AiDecompilationTaskStatus.UNINITIALISED){
// Trigger the decompilation
api.triggerAIDecompilationForFunctionID(fID);
}
Expand All @@ -660,22 +660,20 @@ public String decompileFunctionViaAI(FunctionWithID functionWithID, TaskMonitor
window.setDisplayedValuesBasedOnStatus(function, status);

switch (status.getStatus()) {
case "pending":
case "uninitialised":
case "queued":
case "running":
case PENDING:
case UNINITIALISED:
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
// monitor.incrementProgress(100);
break;
case "success":
case SUCCESS:
monitor.setProgress(monitor.getMaximum());
window.setDisplayedValuesBasedOnStatus(function, status);
return status.getDecompilation();
case "error":
case ERROR:
return "Decompilation failed: %s".formatted(status.getStatus());
default:
throw new RuntimeException("Unknown status: %s".formatted(status.getStatus()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ public BinaryHash upload(Path binPath) throws FileNotFoundException, ApiExceptio
if (!bin.exists())
throw new FileNotFoundException("Binary to upload does not exist");

var result = this.analysisCoreApi.uploadFile(UploadFileType.fromValue("BINARY"), bin, null, true);
var result = this.analysisCoreApi.uploadFile(UploadFileType.fromValue("BINARY"), bin.getAbsolutePath(), null, true);

return new BinaryHash(result.getData().getSha256Hash());
}
Expand Down Expand Up @@ -228,7 +228,7 @@ public List<FunctionInfo> getFunctionInfo(AnalysisID analysisID) {

BaseResponseAnalysisFunctions response = null;
try {
response = this.analysesResultsMetadataApi.getFunctionsList(analysisID.id(), null, null, null);
response = this.analysesResultsMetadataApi.getFunctionsList(analysisID.id(), null, null, null, false, null, null);
} catch (ApiException e) {
throw new RuntimeException("Could not find analysis with ID: " + analysisID.id(), e);
}
Expand Down Expand Up @@ -468,7 +468,8 @@ public GetAiDecompilationTask pollAIDecompileStatus(FunctionID functionID) {
var response = functionsAiDecompilationApi.getAiDecompilationTaskResult(
functionID.value(), // Long functionId
true, // summarise
true // generateInlineComments
true, // generateInlineComments
null // forceRegenerate
);
return response.getData();
} catch (ApiException e) {
Expand Down
7 changes: 4 additions & 3 deletions src/test/java/ai/reveng/AIDecompilerComponentTest.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package ai.reveng;

import ai.reveng.invoker.ApiException;
import ai.reveng.model.AiDecompilationTaskStatus;
import ai.reveng.model.GetAiDecompilationTask;
import ai.reveng.toolkit.ghidra.binarysimilarity.ui.aidecompiler.AIDecompilationdWindow;
import ai.reveng.toolkit.ghidra.core.services.api.AnalysisOptionsBuilder;
Expand Down Expand Up @@ -63,15 +64,15 @@ public List<FunctionInfo> getFunctionInfo(AnalysisID analysisID) {
public GetAiDecompilationTask pollAIDecompileStatus(FunctionID functionID) {
if (functionID.value() == 2) {
return new GetAiDecompilationTask()
.status("success")
.status(AiDecompilationTaskStatus.SUCCESS)
.decompilation("int func2(int a) { return a + 1; }")
.rawDecompilation("int func2(int a) { return a + 1; }")
.summary("Mocked Description Summary for func2")
.aiSummary("Mocked Description Summary for func2")
.rawAiSummary("Summary for func2");
} else if (functionID.value() == 1) {
return new GetAiDecompilationTask()
.status("success")
.status(AiDecompilationTaskStatus.SUCCESS)
.decompilation("void func1() { return; }")
.rawDecompilation("void func1() { return; }")
.summary("Mocked Description Summary")
Expand Down Expand Up @@ -225,7 +226,7 @@ public List<FunctionInfo> getFunctionInfo(AnalysisID analysisID) {
@Override
public GetAiDecompilationTask pollAIDecompileStatus(FunctionID functionID) {
return new GetAiDecompilationTask()
.status("success")
.status(AiDecompilationTaskStatus.SUCCESS)
.decompilation("void func1() { return; }")
.rawDecompilation("void func1() { return; }")
.summary("Mocked Description Summary")
Expand Down
Loading