mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 01:39:21 +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 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
|
||||
*/
|
||||
|
@ -502,6 +520,14 @@ public class DWARFImportOptions {
|
|||
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)}
|
||||
*
|
||||
|
@ -553,6 +579,9 @@ public class DWARFImportOptions {
|
|||
|
||||
options.registerOption(OPTION_SHOW_VARIABLE_STORAGE_INFO, isShowVariableStorageInfo(),
|
||||
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()));
|
||||
setShowVariableStorageInfo(options.getBoolean(OPTION_SHOW_VARIABLE_STORAGE_INFO,
|
||||
isShowVariableStorageInfo()));
|
||||
setMacroEnumSetting(options.getEnum(OPTION_MACRO_ENUM_NAME, getMacroEnumSetting()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ public class DWARFImportSummary {
|
|||
// member variables are package access
|
||||
long dataTypeElapsedMS;
|
||||
long funcsElapsedMS;
|
||||
long macroElapsedMS;
|
||||
long totalElapsedMS;
|
||||
|
||||
int dataTypesAdded;
|
||||
|
@ -39,6 +40,7 @@ public class DWARFImportSummary {
|
|||
Set<String> typeRemappings = new HashSet<>();
|
||||
int paramZeroLenDataType;
|
||||
public int badSourceFileCount;
|
||||
public int numEnumsCreated;
|
||||
|
||||
Set<Integer> dwarfVers = new HashSet<>();
|
||||
int compUnitCount;
|
||||
|
@ -76,6 +78,13 @@ public class DWARFImportSummary {
|
|||
Msg.info(this,
|
||||
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()) {
|
||||
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.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.SourceFileAddr;
|
||||
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;
|
||||
|
||||
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(" ] <==");
|
||||
}
|
||||
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);
|
||||
sb.append(String.format(" /* dest index: %d, offset: %03x */", destIndex,
|
||||
(int) destOffset));
|
||||
|
@ -221,5 +224,4 @@ public class DWARFExpression {
|
|||
return Objects.equals(instructions, other.instructions);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue