GP-5984 create enums from DWARF macro info entries

This commit is contained in:
James 2025-09-12 12:47:14 +00:00
parent 5fbb052b28
commit 3b01f15e1c
5 changed files with 182 additions and 2 deletions

View file

@ -141,6 +141,24 @@ public class DWARFImportOptions {
private boolean showVariableStorageInfo = false; private boolean showVariableStorageInfo = false;
private boolean useStaticStackFrameRegisterValue = true; private boolean useStaticStackFrameRegisterValue = true;
/**
* Used to control which macro info entries are used to create enums.
*/
public static enum MacroEnumSetting {
NONE,
IGNORE_COMMAND_LINE,
ALL;
}
private static final MacroEnumSetting OPTION_DEFAULT_MACRO_ENUM_SETTING =
MacroEnumSetting.IGNORE_COMMAND_LINE;
private MacroEnumSetting macroEnumSetting = OPTION_DEFAULT_MACRO_ENUM_SETTING;
private static final String OPTION_MACRO_ENUM_NAME = "Create Enums from Macros";
private static final String OPTION_MACRO_ENUM_DESC =
"Controls which DWARF macro info entries are used to create enums";
/** /**
* Create new instance * Create new instance
*/ */
@ -502,6 +520,14 @@ public class DWARFImportOptions {
this.useStaticStackFrameRegisterValue = useStaticStackFrameRegisterValue; this.useStaticStackFrameRegisterValue = useStaticStackFrameRegisterValue;
} }
public MacroEnumSetting getMacroEnumSetting() {
return macroEnumSetting;
}
public void setMacroEnumSetting(MacroEnumSetting setting) {
macroEnumSetting = setting;
}
/** /**
* See {@link Analyzer#registerOptions(Options, ghidra.program.model.listing.Program)} * See {@link Analyzer#registerOptions(Options, ghidra.program.model.listing.Program)}
* *
@ -553,6 +579,9 @@ public class DWARFImportOptions {
options.registerOption(OPTION_SHOW_VARIABLE_STORAGE_INFO, isShowVariableStorageInfo(), options.registerOption(OPTION_SHOW_VARIABLE_STORAGE_INFO, isShowVariableStorageInfo(),
null, OPTION_SHOW_VARIABLE_STORAGE_DESC); null, OPTION_SHOW_VARIABLE_STORAGE_DESC);
options.registerOption(OPTION_MACRO_ENUM_NAME, getMacroEnumSetting(), null,
OPTION_MACRO_ENUM_DESC);
} }
/** /**
@ -587,5 +616,6 @@ public class DWARFImportOptions {
setCharsetName(options.getString(OPTION_CHARSET_NAME, getCharsetName())); setCharsetName(options.getString(OPTION_CHARSET_NAME, getCharsetName()));
setShowVariableStorageInfo(options.getBoolean(OPTION_SHOW_VARIABLE_STORAGE_INFO, setShowVariableStorageInfo(options.getBoolean(OPTION_SHOW_VARIABLE_STORAGE_INFO,
isShowVariableStorageInfo())); isShowVariableStorageInfo()));
setMacroEnumSetting(options.getEnum(OPTION_MACRO_ENUM_NAME, getMacroEnumSetting()));
} }
} }

View file

@ -27,6 +27,7 @@ public class DWARFImportSummary {
// member variables are package access // member variables are package access
long dataTypeElapsedMS; long dataTypeElapsedMS;
long funcsElapsedMS; long funcsElapsedMS;
long macroElapsedMS;
long totalElapsedMS; long totalElapsedMS;
int dataTypesAdded; int dataTypesAdded;
@ -39,6 +40,7 @@ public class DWARFImportSummary {
Set<String> typeRemappings = new HashSet<>(); Set<String> typeRemappings = new HashSet<>();
int paramZeroLenDataType; int paramZeroLenDataType;
public int badSourceFileCount; public int badSourceFileCount;
public int numEnumsCreated;
Set<Integer> dwarfVers = new HashSet<>(); Set<Integer> dwarfVers = new HashSet<>();
int compUnitCount; int compUnitCount;
@ -76,6 +78,13 @@ public class DWARFImportSummary {
Msg.info(this, Msg.info(this,
String.format("DWARF function signatures added: %d", funcSignaturesAdded)); String.format("DWARF function signatures added: %d", funcSignaturesAdded));
} }
if (numEnumsCreated > 0) {
Msg.info(this,
"DWARF enums created from macro info entries: %d".formatted(numEnumsCreated));
}
if (macroElapsedMS > 0) {
Msg.info(this, "DWARF enums from macros - elapsed: %dms".formatted(macroElapsedMS));
}
if (!compDirs.isEmpty()) { if (!compDirs.isEmpty()) {
Msg.info(this, "DWARF compile dirs: " + getSortedSet(compDirs).toString()); Msg.info(this, "DWARF compile dirs: " + getSortedSet(compDirs).toString());
} }

View file

@ -22,6 +22,7 @@ import org.apache.commons.io.FilenameUtils;
import ghidra.app.plugin.core.datamgr.util.DataTypeUtils; import ghidra.app.plugin.core.datamgr.util.DataTypeUtils;
import ghidra.app.util.bin.BinaryReader; import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.format.dwarf.DWARFImportOptions.MacroEnumSetting;
import ghidra.app.util.bin.format.dwarf.line.DWARFLine; import ghidra.app.util.bin.format.dwarf.line.DWARFLine;
import ghidra.app.util.bin.format.dwarf.line.DWARFLine.SourceFileAddr; import ghidra.app.util.bin.format.dwarf.line.DWARFLine.SourceFileAddr;
import ghidra.app.util.bin.format.dwarf.line.DWARFLine.SourceFileInfo; import ghidra.app.util.bin.format.dwarf.line.DWARFLine.SourceFileInfo;
@ -427,9 +428,17 @@ public class DWARFImporter {
} }
} }
} }
MacroEnumSetting setting = importOptions.getMacroEnumSetting();
if (!setting.equals(MacroEnumSetting.NONE)) {
long macro_ts = System.currentTimeMillis();
DWARFMacroEnumCreator enumCreator = new DWARFMacroEnumCreator(prog);
enumCreator.createEnumsFromMacroInfo(setting.equals(MacroEnumSetting.ALL), monitor);
importSummary.macroElapsedMS = System.currentTimeMillis() - macro_ts;
}
importSummary.totalElapsedMS = System.currentTimeMillis() - start_ts; importSummary.totalElapsedMS = System.currentTimeMillis() - start_ts;
return importSummary; return importSummary;
} }
} }

View file

@ -0,0 +1,130 @@
/* ###
* IP: GHIDRA
*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.util.bin.format.dwarf;
import java.io.IOException;
import java.util.*;
import generic.expressions.*;
import ghidra.app.util.bin.format.dwarf.macro.DWARFMacroHeader;
import ghidra.app.util.bin.format.dwarf.macro.entry.*;
import ghidra.app.util.bin.format.dwarf.macro.entry.DWARFMacroDefine.MacroInfo;
import ghidra.program.model.data.*;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
/**
* Creates Enum data types in the program from DWARF macro info entries. Each macro
* that can be resolved to a long value results in an Enum datatype with a single
* value
*/
public class DWARFMacroEnumCreator {
private DWARFProgram dprog;
private Set<String> processedMacros;
public static final String ENUM_PATH = "_DEFINES_";
/**
* Constructor
* @param dprog DWARF Program
*/
public DWARFMacroEnumCreator(DWARFProgram dprog) {
this.dprog = dprog;
processedMacros = new HashSet<>();
}
/**
* Creates Ghidra Enums from DWARF macro info entries.
* <p>
* The enums are placed in the program_name/DWARF/_DEFINES_ category path.
* Only one Enum is created for a given name. Creating multiple
* Enums for redefined or multiply-defined macros in not current supported.
* Each value in an enum given a comment consisting of the name of the
* corresponding compilation unit.
*
*
* @param includeCommandLineDefines if false, macros passed on the command line are ignored
* @param monitor monitor
* @throws CancelledException if user cancels
* @throws IOException if error reading macro info
*/
public void createEnumsFromMacroInfo(boolean includeCommandLineDefines, TaskMonitor monitor)
throws CancelledException, IOException {
monitor.initialize(dprog.getCompilationUnits().size());
CategoryPath catPath = DWARFProgram.DWARF_ROOT_CATPATH.extend(ENUM_PATH);
for (DWARFCompilationUnit cu : dprog.getCompilationUnits()) {
monitor.increment();
monitor.setMessage("DWARF: Processing Macros for " + cu.getName());
Map<String, ExpressionValue> macrosToValues = new HashMap<>();
createEnums(cu.getMacros(), macrosToValues, catPath, includeCommandLineDefines,
monitor);
}
}
private void createEnums(DWARFMacroHeader macroHeader,
Map<String, ExpressionValue> macrosToValues, CategoryPath catPath,
boolean includeCommandLineDefines, TaskMonitor monitor)
throws IOException, CancelledException {
DataTypeManager dtManager = dprog.getGhidraProgram().getDataTypeManager();
DWARFImportSummary importSummary = dprog.getImportSummary();
for (DWARFMacroInfoEntry macroEntry : macroHeader.getEntries()) {
monitor.checkCancelled();
switch (macroEntry) {
case DWARFMacroUndef undef:
macrosToValues.remove(undef.getMacroInfo().symbolName());
break;
case DWARFMacroDefine define:
MacroInfo macroInfo = define.getMacroInfo();
if (!macroInfo.isFunctionLike()) {
if (!includeCommandLineDefines && define.getLineNumber() == 0) {
break;
}
String symbolName = macroInfo.symbolName();
if (processedMacros.contains(symbolName)) {
break;
}
processedMacros.add(symbolName);
try {
ExpressionEvaluator evaluator =
new ExpressionEvaluator(s -> macrosToValues.get(s));
long value = evaluator.parseAsLong(macroInfo.definition());
macrosToValues.put(symbolName, new LongExpressionValue(value));
EnumDataType enumDT =
new EnumDataType(catPath, "define_" + symbolName, 8,
dtManager);
enumDT.add(symbolName, value,
macroHeader.getCompilationUnit().getName());
importSummary.numEnumsCreated++;
enumDT.setLength(enumDT.getMinimumPossibleLength());
dtManager.addDataType(enumDT,
DataTypeConflictHandler.KEEP_HANDLER);
}
catch (ExpressionException e) {
// couldn't get numeric value for macro, just skip
}
}
break;
case DWARFMacroImport importMacro:
createEnums(importMacro.getImportedMacroHeader(), macrosToValues,
catPath, includeCommandLineDefines, monitor);
break;
default:
break;
}
}
}
}

View file

@ -194,7 +194,10 @@ public class DWARFExpression {
sb.append(" ] <=="); sb.append(" ] <==");
} }
if (instr.opcode == DW_OP_bra || instr.opcode == DW_OP_skip) { if (instr.opcode == DW_OP_bra || instr.opcode == DW_OP_skip) {
long destOffset = instr.getOperandValue(0) + instr.getOffset(); long destOffset = instr.getOffset();
if (instr.getOperandCount() > 0) {
destOffset += instr.getOperandValue(0);
}
int destIndex = findInstructionByOffset(destOffset); int destIndex = findInstructionByOffset(destOffset);
sb.append(String.format(" /* dest index: %d, offset: %03x */", destIndex, sb.append(String.format(" /* dest index: %d, offset: %03x */", destIndex,
(int) destOffset)); (int) destOffset));
@ -221,5 +224,4 @@ public class DWARFExpression {
return Objects.equals(instructions, other.instructions); return Objects.equals(instructions, other.instructions);
} }
} }