Skip to content

Commit

Permalink
Merge pull request #18 from chaoticgd/symboltablefixes3
Browse files Browse the repository at this point in the history
stabs: Fix type deduplication issues, type naming issues, only run once
  • Loading branch information
chaoticgd authored Feb 20, 2023
2 parents 654f6f5 + 4b57d82 commit da85c46
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 25 deletions.
21 changes: 12 additions & 9 deletions os/download.sh
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
#!/bin/bash
set -e

# Downloads a release of ccc and puts all the stdump executables in the right
# places. This file is called by the CI workflow for putting out new releases.

version='v1.1'

pushd $(dirname -- "$0")
wget https://github.com/chaoticgd/ccc/releases/download/v1.0/ccc_v1.0_linux.zip
wget https://github.com/chaoticgd/ccc/releases/download/v1.0/ccc_v1.0_mac.zip
wget https://github.com/chaoticgd/ccc/releases/download/v1.0/ccc_v1.0_windows.zip
wget "https://github.com/chaoticgd/ccc/releases/download/$(echo $version)/ccc_$(echo $version)_linux.zip"
wget "https://github.com/chaoticgd/ccc/releases/download/$(echo $version)/ccc_$(echo $version)_mac.zip"
wget "https://github.com/chaoticgd/ccc/releases/download/$(echo $version)/ccc_$(echo $version)_windows.zip"
mkdir linux_x86_64
mkdir mac_x86_64
mkdir win_x86_64
unzip -j ccc_v1.0_linux.zip ccc_v1.0_linux/stdump -d linux_x86_64
unzip -j ccc_v1.0_mac.zip ccc_v1.0_mac/stdump -d mac_x86_64
unzip -j ccc_v1.0_windows.zip ccc_v1.0_windows/stdump.exe -d win_x86_64
rm ccc_v1.0_linux.zip
rm ccc_v1.0_mac.zip
rm ccc_v1.0_windows.zip
unzip -j "ccc_$(echo $version)_linux.zip" "ccc_$(echo $version)_linux/stdump" -d linux_x86_64
unzip -j "ccc_$(echo $version)_mac.zip" "ccc_$(echo $version)_mac/stdump" -d mac_x86_64
unzip -j "ccc_$(echo $version)_windows.zip" "ccc_$(echo $version)_windows/stdump.exe" -d win_x86_64
rm "ccc_$(echo $version)_linux.zip"
rm "ccc_$(echo $version)_mac.zip"
rm "ccc_$(echo $version)_windows.zip"
popd
16 changes: 11 additions & 5 deletions src/main/java/ghidra/emotionengine/symboltable/StabsAnalyzer.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public class StabsAnalyzer extends AbstractAnalyzer {
" instructions there).\n\n" +
"For more information see:\n" +
"https://github.com/chaoticgd/ccc";

public static final String OPTION_IMPORT_FUNCTIONS = "Import Functions";
public static final String OPTION_IMPORT_FUNCTIONS_DESC =
"Import functions from the symbol table into Ghidra.";
Expand All @@ -43,6 +43,10 @@ public class StabsAnalyzer extends AbstractAnalyzer {
public static final String OPTION_LINE_NUMBERS_DESC =
"Output source line numbers as end-of-line comments that will appear in the diassembly.";

public static final String OPTION_ONLY_RUN_ONCE = "Only Run Once";
public static final String OPTION_ONLY_RUN_ONCE_DESC =
"Bail out if over 50% of the recovered types already exist to prevent the user from accidentally corrupting their file.";

public static final String OPTION_OVERRIDE_ELF_PATH = "Override ELF Path (Optional)";
public static final String OPTION_OVERRIDE_ELF_PATH_DESC =
"Use and ELF file of your choice as input to stdump instead of the currently loaded program.";
Expand Down Expand Up @@ -82,10 +86,11 @@ public boolean added(Program program, AddressSetView set, TaskMonitor monitor, M

@Override
public void registerOptions(Options options, Program program) {
options.registerOption(OPTION_IMPORT_FUNCTIONS, DEFAULT_OPTIONS.importFunctions, null, OPTION_IMPORT_FUNCTIONS);
options.registerOption(OPTION_IMPORT_GLOBALS, DEFAULT_OPTIONS.importGlobals, null, OPTION_IMPORT_GLOBALS);
options.registerOption(OPTION_INLINED_CODE, DEFAULT_OPTIONS.markInlinedCode, null, OPTION_INLINED_CODE);
options.registerOption(OPTION_LINE_NUMBERS, DEFAULT_OPTIONS.outputLineNumbers, null, OPTION_LINE_NUMBERS);
options.registerOption(OPTION_IMPORT_FUNCTIONS, DEFAULT_OPTIONS.importFunctions, null, OPTION_IMPORT_FUNCTIONS_DESC);
options.registerOption(OPTION_IMPORT_GLOBALS, DEFAULT_OPTIONS.importGlobals, null, OPTION_IMPORT_GLOBALS_DESC);
options.registerOption(OPTION_INLINED_CODE, DEFAULT_OPTIONS.markInlinedCode, null, OPTION_INLINED_CODE_DESC);
options.registerOption(OPTION_LINE_NUMBERS, DEFAULT_OPTIONS.outputLineNumbers, null, OPTION_LINE_NUMBERS_DESC);
options.registerOption(OPTION_ONLY_RUN_ONCE, DEFAULT_OPTIONS.onlyRunOnce, null, OPTION_ONLY_RUN_ONCE_DESC);
options.registerOption(OPTION_OVERRIDE_ELF_PATH, DEFAULT_OPTIONS.overrideElfPath, null, OPTION_OVERRIDE_ELF_PATH_DESC);
options.registerOption(OPTION_OVERRIDE_JSON_PATH, DEFAULT_OPTIONS.overrideJsonPath, null, OPTION_OVERRIDE_JSON_PATH_DESC);
}
Expand All @@ -96,6 +101,7 @@ public void optionsChanged(Options options, Program program) {
importOptions.importGlobals = options.getBoolean(OPTION_IMPORT_GLOBALS, DEFAULT_OPTIONS.importGlobals);
importOptions.markInlinedCode = options.getBoolean(OPTION_INLINED_CODE, DEFAULT_OPTIONS.markInlinedCode);
importOptions.outputLineNumbers = options.getBoolean(OPTION_LINE_NUMBERS, DEFAULT_OPTIONS.outputLineNumbers);
importOptions.onlyRunOnce = options.getBoolean(OPTION_ONLY_RUN_ONCE, DEFAULT_OPTIONS.onlyRunOnce);
importOptions.overrideElfPath = options.getString(OPTION_OVERRIDE_ELF_PATH, DEFAULT_OPTIONS.overrideElfPath);
importOptions.overrideJsonPath = options.getString(OPTION_OVERRIDE_JSON_PATH, DEFAULT_OPTIONS.overrideJsonPath);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import ghidra.program.model.address.AddressSet;
import ghidra.program.model.address.AddressSpace;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.DataTypeManager;
import ghidra.program.model.data.DataUtilities;
import ghidra.program.model.data.DataUtilities.ClearDataMode;
import ghidra.program.model.data.PointerDataType;
Expand All @@ -47,6 +48,7 @@ public static class ImportOptions {
boolean importGlobals = true;
boolean markInlinedCode = true;
boolean outputLineNumbers = true;
boolean onlyRunOnce = true;
String overrideElfPath = "";
String overrideJsonPath = "";
}
Expand Down Expand Up @@ -139,6 +141,7 @@ public boolean doImport() {
cleanupTemporaryFiles();

if(monitor.isCancelled()) {
log.appendMsg("STABS", "Import operation cancelled by user.");
return false;
}

Expand All @@ -152,7 +155,14 @@ public boolean doImport() {
return false;
}

if(options.onlyRunOnce && shouldBailOut(program, ast)) {
log.appendMsg("STABS", "Import operation cancelled since it has already been run.");
return false;
}


if(monitor.isCancelled()) {
log.appendMsg("STABS", "Import operation cancelled by user.");
return false;
}

Expand Down Expand Up @@ -184,6 +194,24 @@ public void cleanupTemporaryFiles() {
temporaryFiles.clear();
}

public boolean shouldBailOut(Program program, StdumpAST.ParsedJsonFile ast) {
if(ast.deduplicatedTypes.size() < 10) {
return false;
}
DataTypeManager dataTypeManager = program.getDataTypeManager();
int existingTypes = 0;
int newTypes = 0;
for(StdumpAST.Node node : ast.deduplicatedTypes) {
if(dataTypeManager.getDataType("/" + node.name) != null) {
existingTypes++;
} else {
newTypes++;
}
}
return existingTypes > newTypes;
}


public void importDataTypes(StdumpAST.ImporterState importer) {
int type_count = importer.ast.deduplicatedTypes.size();

Expand All @@ -207,13 +235,14 @@ public void importDataTypes(StdumpAST.ImporterState importer) {
// Create all the top-level enums, structs and unions first.
for(int i = 0; i < type_count; i++) {
StdumpAST.Node node = importer.ast.deduplicatedTypes.get(i);
node.setupConflictResolutionPostfix(importer);
if(node instanceof StdumpAST.InlineEnum) {
StdumpAST.InlineEnum inlineEnum = (StdumpAST.InlineEnum) node;
DataType type = inlineEnum.createType(importer);
importer.types.add(importer.programTypeManager.addDataType(type, null));
} else if(node instanceof StdumpAST.InlineStructOrUnion) {
StdumpAST.InlineStructOrUnion structOrUnion = (StdumpAST.InlineStructOrUnion) node;
DataType type = structOrUnion.create_empty(importer);
DataType type = structOrUnion.createEmpty(importer);
importer.types.add(importer.programTypeManager.addDataType(type, null));
} else {
importer.types.add(null);
Expand All @@ -224,6 +253,7 @@ public void importDataTypes(StdumpAST.ImporterState importer) {
// Fill in the structs and unions recursively.
for(int i = 0; i < type_count; i++) {
StdumpAST.Node node = importer.ast.deduplicatedTypes.get(i);
node.setupConflictResolutionPostfix(importer);
if(node instanceof StdumpAST.InlineStructOrUnion) {
StdumpAST.InlineStructOrUnion struct_or_union = (StdumpAST.InlineStructOrUnion) node;
DataType type = importer.types.get(i);
Expand Down
27 changes: 18 additions & 9 deletions src/main/java/ghidra/emotionengine/symboltable/StdumpAST.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ public static class ImporterState {
ArrayList<DataType> types = new ArrayList<>(); // (data type, size in bytes)
ArrayList<HashMap<Integer, Integer>> stabsTypeNumberToDeduplicatedTypeIndex = new ArrayList<>();
HashMap<String, Integer> typeNameToDeduplicatedTypeIndex = new HashMap<>();
String conflictResolutionPostfix;

// Ghidra objects.
TaskMonitor monitor;
Expand Down Expand Up @@ -104,11 +105,19 @@ public DataType createTypeImpl(ImporterState importer) {
return Undefined1DataType.dataType;
}

String generateName() {
if(conflict || name == null || name.isEmpty()) {
return prefix + name + "__" + Integer.toString(firstFile) + "_" + Integer.toString(stabsTypeNumber);
void setupConflictResolutionPostfix(ImporterState importer) {
if(conflict) {
importer.conflictResolutionPostfix = "__" + Integer.toString(firstFile) + "_" + Integer.toString(stabsTypeNumber);
} else {
importer.conflictResolutionPostfix = "";
}
}

String generateName(ImporterState importer) {
if(name == null || name.isEmpty()) {
return prefix + "__unnamed_" + Integer.toString(absoluteOffsetBytes) + importer.conflictResolutionPostfix;
}
return prefix + name;
return prefix + name + importer.conflictResolutionPostfix;
}
}

Expand Down Expand Up @@ -221,7 +230,7 @@ public static class InlineEnum extends Node {
ArrayList<EnumConstant> constants = new ArrayList<EnumConstant>();

public DataType createTypeImpl(ImporterState importer) {
EnumDataType type = new EnumDataType(generateName(), 4);
EnumDataType type = new EnumDataType(generateName(importer), 4);
for(EnumConstant constant : constants) {
type.add(constant.name, constant.value);
}
Expand All @@ -236,13 +245,13 @@ public static class InlineStructOrUnion extends Node {
ArrayList<Node> memberFunctions = new ArrayList<Node>();

public DataType createTypeImpl(ImporterState importer) {
DataType result = create_empty(importer);
DataType result = createEmpty(importer);
fill(result, importer);
return result;
}

public DataType create_empty(ImporterState importer) {
String typeName = generateName();
public DataType createEmpty(ImporterState importer) {
String typeName = generateName(importer);
int sizeBytes = sizeBits / 8;
DataType type;
if(isStruct) {
Expand Down Expand Up @@ -296,7 +305,7 @@ public DataType createVtable(ImporterState importer) {
}
}
int vtableSize = (maxVtableIndex + 1) * 4;
StructureDataType vtable = new StructureDataType(generateName() + "__vtable", vtableSize, importer.programTypeManager);
StructureDataType vtable = new StructureDataType(generateName(importer) + "__vtable", vtableSize, importer.programTypeManager);
for(Node node : memberFunctions) {
if(node instanceof FunctionType) {
FunctionType function = (FunctionType) node;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import com.google.gson.stream.JsonReader;

public class StdumpParser {
public static final String SUPPORTED_STDUMP_VERSION = "v1.0";
public static final String SUPPORTED_STDUMP_VERSION = "v1.1";
public static final int SUPPORTED_FORMAT_VERSION = 7;

public static StdumpAST.ParsedJsonFile readJson(byte[] json) throws FileNotFoundException {
Expand Down

0 comments on commit da85c46

Please sign in to comment.