Skip to content

Commit f00de10

Browse files
committed
Merge remote-tracking branch 'origin/GP-4123_ryanmkurtz_cppexporter'
(Closes NationalSecurityAgency#2635)
2 parents 90c7731 + 7559acf commit f00de10

File tree

3 files changed

+47
-34
lines changed

3 files changed

+47
-34
lines changed

Ghidra/Features/Base/src/main/help/help/topics/ExporterPlugin/exporter.htm

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,8 @@ <H4>C/C++ Options</H4>
275275
<LI><B>Use C++ Style Comments (//)</B> - Select to use // or /* style comments.</LI>
276276

277277
<LI><B>Emit Data-type Definitions</B> - Select to export a C/C++ definition for each data-type.</LI>
278+
279+
<LI><B>Emit Referenced Globals</B> - Select to export a C/C++ declaration for referended global variable.</LI>
278280

279281
<LI><B>Function Tags to Filter</B> - Optional list of function tags to filter which
280282
functions are exported. Multiple tags must be comma separated. Any tags listed will
Loading

Ghidra/Features/Decompiler/src/main/java/ghidra/app/util/exporter/CppExporter.java

Lines changed: 45 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
66
* You may obtain a copy of the License at
7-
*
7+
*
88
* http://www.apache.org/licenses/LICENSE-2.0
9-
*
9+
*
1010
* Unless required by applicable law or agreed to in writing, software
1111
* distributed under the License is distributed on an "AS IS" BASIS,
1212
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -47,6 +47,7 @@ public class CppExporter extends Exporter {
4747
public static final String CREATE_HEADER_FILE = "Create Header File (.h)";
4848
public static final String USE_CPP_STYLE_COMMENTS = "Use C++ Style Comments (//)";
4949
public static final String EMIT_TYPE_DEFINITONS = "Emit Data-type Definitions";
50+
public static final String EMIT_REFERENCED_GLOBALS = "Emit Referenced Globals";
5051
public static final String FUNCTION_TAG_FILTERS = "Function Tags to Filter";
5152
public static final String FUNCTION_TAG_EXCLUDE = "Function Tags Excluded";
5253

@@ -56,6 +57,7 @@ public class CppExporter extends Exporter {
5657
private boolean isCreateCFile = true;
5758
private boolean isUseCppStyleComments = true;
5859
private boolean emitDataTypeDefinitions = true;
60+
private boolean emitReferencedGlobals = true;
5961
private String tagOptions = "";
6062

6163
private Set<FunctionTag> functionTagSet = new HashSet<>();
@@ -69,7 +71,7 @@ public CppExporter() {
6971
}
7072

7173
public CppExporter(DecompileOptions options, boolean createHeader, boolean createFile,
72-
boolean emitTypes, boolean excludeTags, String tags) {
74+
boolean emitTypes, boolean emitGlobals, boolean excludeTags, String tags) {
7375
this();
7476
this.options = options;
7577
if (options != null) {
@@ -78,6 +80,7 @@ public CppExporter(DecompileOptions options, boolean createHeader, boolean creat
7880
isCreateHeaderFile = createHeader;
7981
isCreateCFile = createFile;
8082
emitDataTypeDefinitions = emitTypes;
83+
emitReferencedGlobals = emitGlobals;
8184
excludeMatchingTags = excludeTags;
8285
if (tags != null) {
8386
tagOptions = tags;
@@ -164,13 +167,14 @@ private void decompileAndExport(AddressSetView addrSet, Program program,
164167
Listing listing = program.getListing();
165168
FunctionIterator iterator = listing.getFunctions(addrSet, true);
166169
List<Function> functions = new ArrayList<>();
170+
Set<String> processedGlobals = new HashSet<>();
167171
for (int i = 0; iterator.hasNext(); i++) {
168172
//
169173
// Write results every so many items so that we don't blow out memory
170174
//
171175
if (i % 10000 == 0) {
172176
List<CPPResult> results = parallelDecompiler.decompileFunctions(functions);
173-
writeResults(results, headerWriter, cFileWriter, chunkingMonitor);
177+
writeResults(results, processedGlobals, headerWriter, cFileWriter, chunkingMonitor);
174178
functions.clear();
175179
}
176180

@@ -184,7 +188,7 @@ private void decompileAndExport(AddressSetView addrSet, Program program,
184188

185189
// handle any remaining functions
186190
List<CPPResult> results = parallelDecompiler.decompileFunctions(functions);
187-
writeResults(results, headerWriter, cFileWriter, chunkingMonitor);
191+
writeResults(results, processedGlobals, headerWriter, cFileWriter, chunkingMonitor);
188192
}
189193

190194
private boolean excludeFunction(Function currentFunction) {
@@ -205,26 +209,37 @@ private boolean excludeFunction(Function currentFunction) {
205209
return excludeMatchingTags == hasTag;
206210
}
207211

208-
private void writeResults(List<CPPResult> results, PrintWriter headerWriter,
209-
PrintWriter cFileWriter, TaskMonitor monitor) throws CancelledException {
212+
private void writeResults(List<CPPResult> results, Set<String> processedGlobals,
213+
PrintWriter headerWriter, PrintWriter cFileWriter, TaskMonitor monitor)
214+
throws CancelledException {
210215
monitor.checkCancelled();
211216

212217
Collections.sort(results);
213218

219+
StringBuilder globalDecls = new StringBuilder();
214220
StringBuilder headers = new StringBuilder();
215221
StringBuilder bodies = new StringBuilder();
222+
216223
for (CPPResult result : results) {
217224
monitor.checkCancelled();
218225
if (result == null) {
219226
continue;
220227
}
221-
String headerCode = result.getHeaderCode();
228+
if (emitReferencedGlobals) {
229+
for (String global : result.globals()) {
230+
if (processedGlobals.add(global)) {
231+
globalDecls.append(global);
232+
globalDecls.append(EOL);
233+
}
234+
}
235+
}
236+
String headerCode = result.headerCode();
222237
if (headerCode != null) {
223238
headers.append(headerCode);
224239
headers.append(EOL);
225240
}
226241

227-
String bodyCode = result.getBodyCode();
242+
String bodyCode = result.bodyCode();
228243
if (bodyCode != null) {
229244
bodies.append(bodyCode);
230245
bodies.append(EOL);
@@ -237,6 +252,7 @@ private void writeResults(List<CPPResult> results, PrintWriter headerWriter,
237252
headerWriter.println(headers.toString());
238253
}
239254
if (cFileWriter != null) {
255+
cFileWriter.print(globalDecls.toString());
240256
cFileWriter.print(bodies.toString());
241257
}
242258
}
@@ -343,6 +359,7 @@ public List<Option> getOptions(DomainObjectService domainObjectService) {
343359
list.add(new Option(CREATE_C_FILE, Boolean.valueOf(isCreateCFile)));
344360
list.add(new Option(USE_CPP_STYLE_COMMENTS, Boolean.valueOf(isUseCppStyleComments)));
345361
list.add(new Option(EMIT_TYPE_DEFINITONS, Boolean.valueOf(emitDataTypeDefinitions)));
362+
list.add(new Option(EMIT_REFERENCED_GLOBALS, Boolean.valueOf(emitReferencedGlobals)));
346363
list.add(new Option(FUNCTION_TAG_FILTERS, tagOptions));
347364
list.add(new Option(FUNCTION_TAG_EXCLUDE, Boolean.valueOf(excludeMatchingTags)));
348365
return list;
@@ -365,6 +382,9 @@ else if (optName.equals(USE_CPP_STYLE_COMMENTS)) {
365382
else if (optName.equals(EMIT_TYPE_DEFINITONS)) {
366383
emitDataTypeDefinitions = ((Boolean) option.getValue()).booleanValue();
367384
}
385+
else if (optName.equals(EMIT_REFERENCED_GLOBALS)) {
386+
emitReferencedGlobals = ((Boolean) option.getValue()).booleanValue();
387+
}
368388
else if (optName.equals(FUNCTION_TAG_FILTERS)) {
369389
tagOptions = (String) option.getValue();
370390
}
@@ -452,31 +472,12 @@ private static String getFakeCTypeDefinitions(DataOrganization dataOrganization)
452472
// Inner Classes
453473
//==================================================================================================
454474

455-
private class CPPResult implements Comparable<CPPResult> {
456-
457-
private Address address;
458-
private String bodyCode;
459-
private String headerCode;
460-
461-
CPPResult(Address address, String headerCode, String bodyCode) {
462-
this.address = address;
463-
this.headerCode = headerCode;
464-
this.bodyCode = bodyCode;
465-
}
466-
467-
String getHeaderCode() {
468-
return headerCode;
469-
}
470-
471-
String getBodyCode() {
472-
return bodyCode;
473-
}
474-
475+
private record CPPResult(Address address, String headerCode, String bodyCode,
476+
List<String> globals) implements Comparable<CPPResult> {
475477
@Override
476478
public int compareTo(CPPResult other) {
477479
return address.compareTo(other.address);
478480
}
479-
480481
}
481482

482483
private class DecompilerFactory extends CountingBasicFactory<DecompInterface> {
@@ -492,7 +493,7 @@ public DecompInterface doCreate(int itemNumber) throws IOException {
492493
DecompInterface decompiler = new DecompInterface();
493494
decompiler.setOptions(options);
494495
decompiler.openProgram(program);
495-
decompiler.toggleSyntaxTree(false); // Don't need syntax tree
496+
decompiler.toggleSyntaxTree(true);
496497
return decompiler;
497498
}
498499

@@ -532,7 +533,7 @@ private CPPResult doWork(Function function, DecompInterface decompiler,
532533
CodeUnit codeUnitAt = function.getProgram().getListing().getCodeUnitAt(entryPoint);
533534
if (codeUnitAt == null || !(codeUnitAt instanceof Instruction)) {
534535
return new CPPResult(entryPoint, function.getPrototypeString(false, false) + ';',
535-
null);
536+
null, List.of());
536537
}
537538

538539
monitor.setMessage("Decompiling " + function.getName());
@@ -546,14 +547,24 @@ private CPPResult doWork(Function function, DecompInterface decompiler,
546547
monitor.incrementProgress(1);
547548
return new CPPResult(entryPoint, null,
548549
"/*" + EOL + "Unable to decompile '" + function.getName() + "'" + EOL +
549-
"Cause: " + errorMessage + EOL + "*/" + EOL);
550+
"Cause: " + errorMessage + EOL + "*/" + EOL,
551+
List.of());
550552
}
551553
return null;
552554
}
553555

554556
DecompiledFunction decompiledFunction = dr.getDecompiledFunction();
557+
List<String> globals =
558+
CollectionUtils.asStream(dr.getHighFunction().getGlobalSymbolMap().getSymbols())
559+
.map(hsym -> {
560+
String dt = hsym.getDataType().getDisplayName();
561+
String name = hsym.getName();
562+
String space = dt.endsWith("*") ? "" : " ";
563+
return "%s%s%s;".formatted(dt, space, name);
564+
})
565+
.toList();
555566
return new CPPResult(entryPoint, decompiledFunction.getSignature(),
556-
decompiledFunction.getC());
567+
decompiledFunction.getC(), globals);
557568
}
558569
}
559570

0 commit comments

Comments
 (0)