mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-06-01 07:25:10 +08:00
GP-4123: CppExporter can now emit referenced globals
This commit is contained in:
@@ -275,6 +275,8 @@
|
|||||||
<LI><B>Use C++ Style Comments (//)</B> - Select to use // or /* style comments.</LI>
|
<LI><B>Use C++ Style Comments (//)</B> - Select to use // or /* style comments.</LI>
|
||||||
|
|
||||||
<LI><B>Emit Data-type Definitions</B> - Select to export a C/C++ definition for each data-type.</LI>
|
<LI><B>Emit Data-type Definitions</B> - Select to export a C/C++ definition for each data-type.</LI>
|
||||||
|
|
||||||
|
<LI><B>Emit Referenced Globals</B> - Select to export a C/C++ declaration for referended global variable.</LI>
|
||||||
|
|
||||||
<LI><B>Function Tags to Filter</B> - Optional list of function tags to filter which
|
<LI><B>Function Tags to Filter</B> - Optional list of function tags to filter which
|
||||||
functions are exported. Multiple tags must be comma separated. Any tags listed will
|
functions are exported. Multiple tags must be comma separated. Any tags listed will
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 9.7 KiB |
+45
-34
@@ -4,9 +4,9 @@
|
|||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* 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 CREATE_HEADER_FILE = "Create Header File (.h)";
|
||||||
public static final String USE_CPP_STYLE_COMMENTS = "Use C++ Style Comments (//)";
|
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_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_FILTERS = "Function Tags to Filter";
|
||||||
public static final String FUNCTION_TAG_EXCLUDE = "Function Tags Excluded";
|
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 isCreateCFile = true;
|
||||||
private boolean isUseCppStyleComments = true;
|
private boolean isUseCppStyleComments = true;
|
||||||
private boolean emitDataTypeDefinitions = true;
|
private boolean emitDataTypeDefinitions = true;
|
||||||
|
private boolean emitReferencedGlobals = true;
|
||||||
private String tagOptions = "";
|
private String tagOptions = "";
|
||||||
|
|
||||||
private Set<FunctionTag> functionTagSet = new HashSet<>();
|
private Set<FunctionTag> functionTagSet = new HashSet<>();
|
||||||
@@ -69,7 +71,7 @@ public class CppExporter extends Exporter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public CppExporter(DecompileOptions options, boolean createHeader, boolean createFile,
|
public CppExporter(DecompileOptions options, boolean createHeader, boolean createFile,
|
||||||
boolean emitTypes, boolean excludeTags, String tags) {
|
boolean emitTypes, boolean emitGlobals, boolean excludeTags, String tags) {
|
||||||
this();
|
this();
|
||||||
this.options = options;
|
this.options = options;
|
||||||
if (options != null) {
|
if (options != null) {
|
||||||
@@ -78,6 +80,7 @@ public class CppExporter extends Exporter {
|
|||||||
isCreateHeaderFile = createHeader;
|
isCreateHeaderFile = createHeader;
|
||||||
isCreateCFile = createFile;
|
isCreateCFile = createFile;
|
||||||
emitDataTypeDefinitions = emitTypes;
|
emitDataTypeDefinitions = emitTypes;
|
||||||
|
emitReferencedGlobals = emitGlobals;
|
||||||
excludeMatchingTags = excludeTags;
|
excludeMatchingTags = excludeTags;
|
||||||
if (tags != null) {
|
if (tags != null) {
|
||||||
tagOptions = tags;
|
tagOptions = tags;
|
||||||
@@ -164,13 +167,14 @@ public class CppExporter extends Exporter {
|
|||||||
Listing listing = program.getListing();
|
Listing listing = program.getListing();
|
||||||
FunctionIterator iterator = listing.getFunctions(addrSet, true);
|
FunctionIterator iterator = listing.getFunctions(addrSet, true);
|
||||||
List<Function> functions = new ArrayList<>();
|
List<Function> functions = new ArrayList<>();
|
||||||
|
Set<String> processedGlobals = new HashSet<>();
|
||||||
for (int i = 0; iterator.hasNext(); i++) {
|
for (int i = 0; iterator.hasNext(); i++) {
|
||||||
//
|
//
|
||||||
// Write results every so many items so that we don't blow out memory
|
// Write results every so many items so that we don't blow out memory
|
||||||
//
|
//
|
||||||
if (i % 10000 == 0) {
|
if (i % 10000 == 0) {
|
||||||
List<CPPResult> results = parallelDecompiler.decompileFunctions(functions);
|
List<CPPResult> results = parallelDecompiler.decompileFunctions(functions);
|
||||||
writeResults(results, headerWriter, cFileWriter, chunkingMonitor);
|
writeResults(results, processedGlobals, headerWriter, cFileWriter, chunkingMonitor);
|
||||||
functions.clear();
|
functions.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,7 +188,7 @@ public class CppExporter extends Exporter {
|
|||||||
|
|
||||||
// handle any remaining functions
|
// handle any remaining functions
|
||||||
List<CPPResult> results = parallelDecompiler.decompileFunctions(functions);
|
List<CPPResult> results = parallelDecompiler.decompileFunctions(functions);
|
||||||
writeResults(results, headerWriter, cFileWriter, chunkingMonitor);
|
writeResults(results, processedGlobals, headerWriter, cFileWriter, chunkingMonitor);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean excludeFunction(Function currentFunction) {
|
private boolean excludeFunction(Function currentFunction) {
|
||||||
@@ -205,26 +209,37 @@ public class CppExporter extends Exporter {
|
|||||||
return excludeMatchingTags == hasTag;
|
return excludeMatchingTags == hasTag;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeResults(List<CPPResult> results, PrintWriter headerWriter,
|
private void writeResults(List<CPPResult> results, Set<String> processedGlobals,
|
||||||
PrintWriter cFileWriter, TaskMonitor monitor) throws CancelledException {
|
PrintWriter headerWriter, PrintWriter cFileWriter, TaskMonitor monitor)
|
||||||
|
throws CancelledException {
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
|
|
||||||
Collections.sort(results);
|
Collections.sort(results);
|
||||||
|
|
||||||
|
StringBuilder globalDecls = new StringBuilder();
|
||||||
StringBuilder headers = new StringBuilder();
|
StringBuilder headers = new StringBuilder();
|
||||||
StringBuilder bodies = new StringBuilder();
|
StringBuilder bodies = new StringBuilder();
|
||||||
|
|
||||||
for (CPPResult result : results) {
|
for (CPPResult result : results) {
|
||||||
monitor.checkCancelled();
|
monitor.checkCancelled();
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
continue;
|
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) {
|
if (headerCode != null) {
|
||||||
headers.append(headerCode);
|
headers.append(headerCode);
|
||||||
headers.append(EOL);
|
headers.append(EOL);
|
||||||
}
|
}
|
||||||
|
|
||||||
String bodyCode = result.getBodyCode();
|
String bodyCode = result.bodyCode();
|
||||||
if (bodyCode != null) {
|
if (bodyCode != null) {
|
||||||
bodies.append(bodyCode);
|
bodies.append(bodyCode);
|
||||||
bodies.append(EOL);
|
bodies.append(EOL);
|
||||||
@@ -237,6 +252,7 @@ public class CppExporter extends Exporter {
|
|||||||
headerWriter.println(headers.toString());
|
headerWriter.println(headers.toString());
|
||||||
}
|
}
|
||||||
if (cFileWriter != null) {
|
if (cFileWriter != null) {
|
||||||
|
cFileWriter.print(globalDecls.toString());
|
||||||
cFileWriter.print(bodies.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(CREATE_C_FILE, Boolean.valueOf(isCreateCFile)));
|
||||||
list.add(new Option(USE_CPP_STYLE_COMMENTS, Boolean.valueOf(isUseCppStyleComments)));
|
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_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_FILTERS, tagOptions));
|
||||||
list.add(new Option(FUNCTION_TAG_EXCLUDE, Boolean.valueOf(excludeMatchingTags)));
|
list.add(new Option(FUNCTION_TAG_EXCLUDE, Boolean.valueOf(excludeMatchingTags)));
|
||||||
return list;
|
return list;
|
||||||
@@ -365,6 +382,9 @@ public class CppExporter extends Exporter {
|
|||||||
else if (optName.equals(EMIT_TYPE_DEFINITONS)) {
|
else if (optName.equals(EMIT_TYPE_DEFINITONS)) {
|
||||||
emitDataTypeDefinitions = ((Boolean) option.getValue()).booleanValue();
|
emitDataTypeDefinitions = ((Boolean) option.getValue()).booleanValue();
|
||||||
}
|
}
|
||||||
|
else if (optName.equals(EMIT_REFERENCED_GLOBALS)) {
|
||||||
|
emitReferencedGlobals = ((Boolean) option.getValue()).booleanValue();
|
||||||
|
}
|
||||||
else if (optName.equals(FUNCTION_TAG_FILTERS)) {
|
else if (optName.equals(FUNCTION_TAG_FILTERS)) {
|
||||||
tagOptions = (String) option.getValue();
|
tagOptions = (String) option.getValue();
|
||||||
}
|
}
|
||||||
@@ -452,31 +472,12 @@ public class CppExporter extends Exporter {
|
|||||||
// Inner Classes
|
// Inner Classes
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
|
|
||||||
private class CPPResult implements Comparable<CPPResult> {
|
private record CPPResult(Address address, String headerCode, String bodyCode,
|
||||||
|
List<String> globals) implements Comparable<CPPResult> {
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compareTo(CPPResult other) {
|
public int compareTo(CPPResult other) {
|
||||||
return address.compareTo(other.address);
|
return address.compareTo(other.address);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class DecompilerFactory extends CountingBasicFactory<DecompInterface> {
|
private class DecompilerFactory extends CountingBasicFactory<DecompInterface> {
|
||||||
@@ -492,7 +493,7 @@ public class CppExporter extends Exporter {
|
|||||||
DecompInterface decompiler = new DecompInterface();
|
DecompInterface decompiler = new DecompInterface();
|
||||||
decompiler.setOptions(options);
|
decompiler.setOptions(options);
|
||||||
decompiler.openProgram(program);
|
decompiler.openProgram(program);
|
||||||
decompiler.toggleSyntaxTree(false); // Don't need syntax tree
|
decompiler.toggleSyntaxTree(true);
|
||||||
return decompiler;
|
return decompiler;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -532,7 +533,7 @@ public class CppExporter extends Exporter {
|
|||||||
CodeUnit codeUnitAt = function.getProgram().getListing().getCodeUnitAt(entryPoint);
|
CodeUnit codeUnitAt = function.getProgram().getListing().getCodeUnitAt(entryPoint);
|
||||||
if (codeUnitAt == null || !(codeUnitAt instanceof Instruction)) {
|
if (codeUnitAt == null || !(codeUnitAt instanceof Instruction)) {
|
||||||
return new CPPResult(entryPoint, function.getPrototypeString(false, false) + ';',
|
return new CPPResult(entryPoint, function.getPrototypeString(false, false) + ';',
|
||||||
null);
|
null, List.of());
|
||||||
}
|
}
|
||||||
|
|
||||||
monitor.setMessage("Decompiling " + function.getName());
|
monitor.setMessage("Decompiling " + function.getName());
|
||||||
@@ -546,14 +547,24 @@ public class CppExporter extends Exporter {
|
|||||||
monitor.incrementProgress(1);
|
monitor.incrementProgress(1);
|
||||||
return new CPPResult(entryPoint, null,
|
return new CPPResult(entryPoint, null,
|
||||||
"/*" + EOL + "Unable to decompile '" + function.getName() + "'" + EOL +
|
"/*" + EOL + "Unable to decompile '" + function.getName() + "'" + EOL +
|
||||||
"Cause: " + errorMessage + EOL + "*/" + EOL);
|
"Cause: " + errorMessage + EOL + "*/" + EOL,
|
||||||
|
List.of());
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
DecompiledFunction decompiledFunction = dr.getDecompiledFunction();
|
DecompiledFunction decompiledFunction = dr.getDecompiledFunction();
|
||||||
|
List<String> 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(),
|
return new CPPResult(entryPoint, decompiledFunction.getSignature(),
|
||||||
decompiledFunction.getC());
|
decompiledFunction.getC(), globals);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user