diff --git a/Ghidra/Features/Base/src/main/help/help/topics/ExporterPlugin/exporter.htm b/Ghidra/Features/Base/src/main/help/help/topics/ExporterPlugin/exporter.htm
index 2242bc1a0e..5f0184f19a 100644
--- a/Ghidra/Features/Base/src/main/help/help/topics/ExporterPlugin/exporter.htm
+++ b/Ghidra/Features/Base/src/main/help/help/topics/ExporterPlugin/exporter.htm
@@ -275,6 +275,8 @@
Use C++ Style Comments (//) - Select to use // or /* style comments.
Emit Data-type Definitions - Select to export a C/C++ definition for each data-type.
+
+ Emit Referenced Globals - Select to export a C/C++ declaration for referended global variable.
Function Tags to Filter - Optional list of function tags to filter which
functions are exported. Multiple tags must be comma separated. Any tags listed will
diff --git a/Ghidra/Features/Base/src/main/help/help/topics/ExporterPlugin/images/C_Options.png b/Ghidra/Features/Base/src/main/help/help/topics/ExporterPlugin/images/C_Options.png
index fa516a3f72..6c5f1450e1 100644
Binary files a/Ghidra/Features/Base/src/main/help/help/topics/ExporterPlugin/images/C_Options.png and b/Ghidra/Features/Base/src/main/help/help/topics/ExporterPlugin/images/C_Options.png differ
diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/util/exporter/CppExporter.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/util/exporter/CppExporter.java
index dcbaaea29f..529fceb7a4 100644
--- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/util/exporter/CppExporter.java
+++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/util/exporter/CppExporter.java
@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -47,6 +47,7 @@ public class CppExporter extends Exporter {
public static final String CREATE_HEADER_FILE = "Create Header File (.h)";
public static final String USE_CPP_STYLE_COMMENTS = "Use C++ Style Comments (//)";
public static final String EMIT_TYPE_DEFINITONS = "Emit Data-type Definitions";
+ public static final String EMIT_REFERENCED_GLOBALS = "Emit Referenced Globals";
public static final String FUNCTION_TAG_FILTERS = "Function Tags to Filter";
public static final String FUNCTION_TAG_EXCLUDE = "Function Tags Excluded";
@@ -56,6 +57,7 @@ public class CppExporter extends Exporter {
private boolean isCreateCFile = true;
private boolean isUseCppStyleComments = true;
private boolean emitDataTypeDefinitions = true;
+ private boolean emitReferencedGlobals = true;
private String tagOptions = "";
private Set functionTagSet = new HashSet<>();
@@ -69,7 +71,7 @@ public class CppExporter extends Exporter {
}
public CppExporter(DecompileOptions options, boolean createHeader, boolean createFile,
- boolean emitTypes, boolean excludeTags, String tags) {
+ boolean emitTypes, boolean emitGlobals, boolean excludeTags, String tags) {
this();
this.options = options;
if (options != null) {
@@ -78,6 +80,7 @@ public class CppExporter extends Exporter {
isCreateHeaderFile = createHeader;
isCreateCFile = createFile;
emitDataTypeDefinitions = emitTypes;
+ emitReferencedGlobals = emitGlobals;
excludeMatchingTags = excludeTags;
if (tags != null) {
tagOptions = tags;
@@ -164,13 +167,14 @@ public class CppExporter extends Exporter {
Listing listing = program.getListing();
FunctionIterator iterator = listing.getFunctions(addrSet, true);
List functions = new ArrayList<>();
+ Set processedGlobals = new HashSet<>();
for (int i = 0; iterator.hasNext(); i++) {
//
// Write results every so many items so that we don't blow out memory
//
if (i % 10000 == 0) {
List results = parallelDecompiler.decompileFunctions(functions);
- writeResults(results, headerWriter, cFileWriter, chunkingMonitor);
+ writeResults(results, processedGlobals, headerWriter, cFileWriter, chunkingMonitor);
functions.clear();
}
@@ -184,7 +188,7 @@ public class CppExporter extends Exporter {
// handle any remaining functions
List results = parallelDecompiler.decompileFunctions(functions);
- writeResults(results, headerWriter, cFileWriter, chunkingMonitor);
+ writeResults(results, processedGlobals, headerWriter, cFileWriter, chunkingMonitor);
}
private boolean excludeFunction(Function currentFunction) {
@@ -205,26 +209,37 @@ public class CppExporter extends Exporter {
return excludeMatchingTags == hasTag;
}
- private void writeResults(List results, PrintWriter headerWriter,
- PrintWriter cFileWriter, TaskMonitor monitor) throws CancelledException {
+ private void writeResults(List results, Set processedGlobals,
+ PrintWriter headerWriter, PrintWriter cFileWriter, TaskMonitor monitor)
+ throws CancelledException {
monitor.checkCancelled();
Collections.sort(results);
+ StringBuilder globalDecls = new StringBuilder();
StringBuilder headers = new StringBuilder();
StringBuilder bodies = new StringBuilder();
+
for (CPPResult result : results) {
monitor.checkCancelled();
if (result == null) {
continue;
}
- String headerCode = result.getHeaderCode();
+ if (emitReferencedGlobals) {
+ for (String global : result.globals()) {
+ if (processedGlobals.add(global)) {
+ globalDecls.append(global);
+ globalDecls.append(EOL);
+ }
+ }
+ }
+ String headerCode = result.headerCode();
if (headerCode != null) {
headers.append(headerCode);
headers.append(EOL);
}
- String bodyCode = result.getBodyCode();
+ String bodyCode = result.bodyCode();
if (bodyCode != null) {
bodies.append(bodyCode);
bodies.append(EOL);
@@ -237,6 +252,7 @@ public class CppExporter extends Exporter {
headerWriter.println(headers.toString());
}
if (cFileWriter != null) {
+ cFileWriter.print(globalDecls.toString());
cFileWriter.print(bodies.toString());
}
}
@@ -343,6 +359,7 @@ public class CppExporter extends Exporter {
list.add(new Option(CREATE_C_FILE, Boolean.valueOf(isCreateCFile)));
list.add(new Option(USE_CPP_STYLE_COMMENTS, Boolean.valueOf(isUseCppStyleComments)));
list.add(new Option(EMIT_TYPE_DEFINITONS, Boolean.valueOf(emitDataTypeDefinitions)));
+ list.add(new Option(EMIT_REFERENCED_GLOBALS, Boolean.valueOf(emitReferencedGlobals)));
list.add(new Option(FUNCTION_TAG_FILTERS, tagOptions));
list.add(new Option(FUNCTION_TAG_EXCLUDE, Boolean.valueOf(excludeMatchingTags)));
return list;
@@ -365,6 +382,9 @@ public class CppExporter extends Exporter {
else if (optName.equals(EMIT_TYPE_DEFINITONS)) {
emitDataTypeDefinitions = ((Boolean) option.getValue()).booleanValue();
}
+ else if (optName.equals(EMIT_REFERENCED_GLOBALS)) {
+ emitReferencedGlobals = ((Boolean) option.getValue()).booleanValue();
+ }
else if (optName.equals(FUNCTION_TAG_FILTERS)) {
tagOptions = (String) option.getValue();
}
@@ -452,31 +472,12 @@ public class CppExporter extends Exporter {
// Inner Classes
//==================================================================================================
- private class CPPResult implements Comparable {
-
- private Address address;
- private String bodyCode;
- private String headerCode;
-
- CPPResult(Address address, String headerCode, String bodyCode) {
- this.address = address;
- this.headerCode = headerCode;
- this.bodyCode = bodyCode;
- }
-
- String getHeaderCode() {
- return headerCode;
- }
-
- String getBodyCode() {
- return bodyCode;
- }
-
+ private record CPPResult(Address address, String headerCode, String bodyCode,
+ List globals) implements Comparable {
@Override
public int compareTo(CPPResult other) {
return address.compareTo(other.address);
}
-
}
private class DecompilerFactory extends CountingBasicFactory {
@@ -492,7 +493,7 @@ public class CppExporter extends Exporter {
DecompInterface decompiler = new DecompInterface();
decompiler.setOptions(options);
decompiler.openProgram(program);
- decompiler.toggleSyntaxTree(false); // Don't need syntax tree
+ decompiler.toggleSyntaxTree(true);
return decompiler;
}
@@ -532,7 +533,7 @@ public class CppExporter extends Exporter {
CodeUnit codeUnitAt = function.getProgram().getListing().getCodeUnitAt(entryPoint);
if (codeUnitAt == null || !(codeUnitAt instanceof Instruction)) {
return new CPPResult(entryPoint, function.getPrototypeString(false, false) + ';',
- null);
+ null, List.of());
}
monitor.setMessage("Decompiling " + function.getName());
@@ -546,14 +547,24 @@ public class CppExporter extends Exporter {
monitor.incrementProgress(1);
return new CPPResult(entryPoint, null,
"/*" + EOL + "Unable to decompile '" + function.getName() + "'" + EOL +
- "Cause: " + errorMessage + EOL + "*/" + EOL);
+ "Cause: " + errorMessage + EOL + "*/" + EOL,
+ List.of());
}
return null;
}
DecompiledFunction decompiledFunction = dr.getDecompiledFunction();
+ List globals =
+ CollectionUtils.asStream(dr.getHighFunction().getGlobalSymbolMap().getSymbols())
+ .map(hsym -> {
+ String dt = hsym.getDataType().getDisplayName();
+ String name = hsym.getName();
+ String space = dt.endsWith("*") ? "" : " ";
+ return "%s%s%s;".formatted(dt, space, name);
+ })
+ .toList();
return new CPPResult(entryPoint, decompiledFunction.getSignature(),
- decompiledFunction.getC());
+ decompiledFunction.getC(), globals);
}
}