mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-05-28 12:45:32 +08:00
Merge remote-tracking branch 'origin/GP-4123_ryanmkurtz_cppexporter'
(Closes #2635)
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>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
|
||||
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");
|
||||
* 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<FunctionTag> 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<Function> functions = new ArrayList<>();
|
||||
Set<String> 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<CPPResult> 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<CPPResult> 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<CPPResult> results, PrintWriter headerWriter,
|
||||
PrintWriter cFileWriter, TaskMonitor monitor) throws CancelledException {
|
||||
private void writeResults(List<CPPResult> results, Set<String> 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<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;
|
||||
}
|
||||
|
||||
private record CPPResult(Address address, String headerCode, String bodyCode,
|
||||
List<String> globals) implements Comparable<CPPResult> {
|
||||
@Override
|
||||
public int compareTo(CPPResult other) {
|
||||
return address.compareTo(other.address);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class DecompilerFactory extends CountingBasicFactory<DecompInterface> {
|
||||
@@ -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<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(),
|
||||
decompiledFunction.getC());
|
||||
decompiledFunction.getC(), globals);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user