mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 17:59:46 +02:00
GP-5984 create enums from DWARF macro info entries
This commit is contained in:
parent
5fbb052b28
commit
3b01f15e1c
5 changed files with 182 additions and 2 deletions
|
@ -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()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue