GP-4178 Added ELF Import option to control undefined data creation (now off by default)

This commit is contained in:
ghidra1 2024-01-03 17:41:16 -05:00
parent f739df7c21
commit c5243f9a95
4 changed files with 46 additions and 30 deletions

View file

@ -17,6 +17,7 @@ package ghidra.app.util.bin.format.elf;
import ghidra.app.util.bin.format.MemoryLoadable;
import ghidra.app.util.importer.MessageLog;
import ghidra.app.util.opinion.ElfLoaderOptionsFactory;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressRange;
import ghidra.program.model.data.DataType;
@ -104,10 +105,13 @@ public interface ElfLoadHelper {
Address indirectPointerAddr);
/**
* Create an undefined data item to reserve the location as data, without specifying the type
* Create an undefined data item to reserve the location as data, without specifying the type.
* If {@link ElfLoaderOptionsFactory#applyUndefinedSymbolData(java.util.List)} returns false
* data will not be applied and null will be returned.
*
* @param address location of undefined data to create
* @param length size of the undefined data item
* @return {@link Data} which was created or null if conflict occurs
* @return {@link Data} which was created or null if conflict occurs or disabled by option
*/
Data createUndefinedData(Address address, int length);

View file

@ -34,6 +34,9 @@ public class ElfLoaderOptionsFactory {
public static final String PERFORM_RELOCATIONS_NAME = "Perform Symbol Relocations";
static final boolean PERFORM_RELOCATIONS_DEFAULT = true;
public static final String APPLY_UNDEFINED_SYMBOL_DATA_NAME = "Apply Undefined Symbol Data";
static final boolean APPLY_UNDEFINED_SYMBOL_DATA_DEFAULT = false;
// NOTE: Using too large of an image base can cause problems for relocation processing
// for some language scenarios which utilize 32-bit relocations. This may be due to
// an assumed virtual memory of 32-bits.
@ -41,7 +44,7 @@ public class ElfLoaderOptionsFactory {
public static final String IMAGE_BASE_OPTION_NAME = "Image Base";
public static final long IMAGE_BASE_DEFAULT = 0x00010000;
public static final long IMAGE64_BASE_DEFAULT = 0x00100000L;
public static final String IMAGE_DATA_IMAGE_BASE_OPTION_NAME = "Data Image Base";
public static final String INCLUDE_OTHER_BLOCKS = "Import Non-Loaded Data";// as OTHER overlay blocks
@ -66,6 +69,10 @@ public class ElfLoaderOptionsFactory {
options.add(new Option(PERFORM_RELOCATIONS_NAME, PERFORM_RELOCATIONS_DEFAULT, Boolean.class,
Loader.COMMAND_LINE_ARG_PREFIX + "-applyRelocations"));
options.add(
new Option(APPLY_UNDEFINED_SYMBOL_DATA_NAME, APPLY_UNDEFINED_SYMBOL_DATA_DEFAULT,
Boolean.class, Loader.COMMAND_LINE_ARG_PREFIX + "-applyUndefinedData"));
ElfHeader elf = new ElfHeader(provider, null);
long imageBase = elf.findImageBase();
@ -78,7 +85,7 @@ public class ElfLoaderOptionsFactory {
String hexValueStr = getBaseAddressOffsetString(imageBase, defaultSpace);
options.add(new Option(IMAGE_BASE_OPTION_NAME, hexValueStr, String.class,
Loader.COMMAND_LINE_ARG_PREFIX + "-imagebase"));
if (includeDataImageBaseOption(elf, language)) {
long minDataImageBase = getRecommendedMinimumDataImageBase(elf, language);
hexValueStr =
@ -100,7 +107,7 @@ public class ElfLoaderOptionsFactory {
}
}
private static boolean includeDataImageBaseOption(ElfHeader elf, Language language) {
// only include option if all segments and section have a 0 address
AddressSpace defaultSpace = language.getDefaultSpace();
@ -110,18 +117,18 @@ public class ElfLoaderOptionsFactory {
}
return elf.isRelocatable() && elf.getImageBase() == 0;
}
private static long getRecommendedMinimumDataImageBase(ElfHeader elf, Language language) {
String minDataOffset =
language.getProperty(GhidraLanguagePropertyKeys.MINIMUM_DATA_IMAGE_BASE);
if (minDataOffset != null) {
return NumericUtilities.parseHexLong(minDataOffset);
}
AddressSpace defaultDataSpace = language.getDefaultDataSpace();
int unitSize = defaultDataSpace.getAddressableUnitSize();
// logic assumes memory mapped registers reside at low-end addresses (e.g., 0)
long minOffset = 0;
for (Register reg : language.getRegisters()) {
@ -152,8 +159,7 @@ public class ElfLoaderOptionsFactory {
int minNibbles = Math.min(8, space.getSize() / 4);
int baseOffsetStrLen = baseOffsetStr.length();
if (baseOffsetStrLen < minNibbles) {
baseOffsetStr =
StringUtilities.pad(baseOffsetStr, '0', minNibbles - baseOffsetStrLen);
baseOffsetStr = StringUtilities.pad(baseOffsetStr, '0', minNibbles - baseOffsetStrLen);
}
return baseOffsetStr;
}
@ -162,17 +168,14 @@ public class ElfLoaderOptionsFactory {
Language language;
try {
language = loadSpec.getLanguageCompilerSpec().getLanguage();
} catch (LanguageNotFoundException e) {
}
catch (LanguageNotFoundException e) {
throw new RuntimeException(e);
}
for (Option option : options) {
String name = option.getName();
if (name.equals(PERFORM_RELOCATIONS_NAME)) {
if (!Boolean.class.isAssignableFrom(option.getValueClass())) {
return "Invalid type for option: " + name + " - " + option.getValueClass();
}
}
else if (name.equals(INCLUDE_OTHER_BLOCKS)) {
if (name.equals(PERFORM_RELOCATIONS_NAME) || name.equals(INCLUDE_OTHER_BLOCKS) ||
name.equals(APPLY_UNDEFINED_SYMBOL_DATA_NAME)) {
if (!Boolean.class.isAssignableFrom(option.getValueClass())) {
return "Invalid type for option: " + name + " - " + option.getValueClass();
}
@ -227,6 +230,11 @@ public class ElfLoaderOptionsFactory {
PERFORM_RELOCATIONS_DEFAULT);
}
public static boolean applyUndefinedSymbolData(List<Option> options) {
return OptionUtils.getOption(APPLY_UNDEFINED_SYMBOL_DATA_NAME, options,
APPLY_UNDEFINED_SYMBOL_DATA_DEFAULT);
}
static boolean includeOtherBlocks(List<Option> options) {
return OptionUtils.getOption(INCLUDE_OTHER_BLOCKS, options, INCLUDE_OTHER_BLOCKS_DEFAULT);
}
@ -238,7 +246,7 @@ public class ElfLoaderOptionsFactory {
public static String getImageBaseOption(List<Option> options) {
return OptionUtils.getOption(IMAGE_BASE_OPTION_NAME, options, (String) null);
}
public static String getDataImageBaseOption(List<Option> options) {
return OptionUtils.getOption(IMAGE_DATA_IMAGE_BASE_OPTION_NAME, options, (String) null);
}

View file

@ -1361,12 +1361,22 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
}
private void allocateUndefinedSymbolData(HashMap<Address, Integer> dataAllocationMap) {
if (!ElfLoaderOptionsFactory.applyUndefinedSymbolData(options)) {
return;
}
for (Address addr : dataAllocationMap.keySet()) {
MemoryBlock block = memory.getBlock(addr);
if (block == null) {
continue;
}
// Create undefined data for each data/object symbol
Integer symbolSize = dataAllocationMap.get(addr);
if (symbolSize != null) {
try {
createUndefined(addr, symbolSize);
DataType undefined = Undefined.getUndefinedDataType(symbolSize);
listing.createData(addr, undefined);
}
catch (CodeUnitInsertionException e) {
// ignore conflicts which can be caused by other markup
@ -2311,6 +2321,9 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
@Override
public Data createUndefinedData(Address address, int length) {
if (!ElfLoaderOptionsFactory.applyUndefinedSymbolData(options)) {
return null;
}
try {
// If it is bigger than 8, just let it go through and create a single undefined
// Otherwise this would create an array of undefined, might get in the way
@ -3550,16 +3563,6 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
return StringUtilities.pad("" + value, ' ', 4);
}
private Data createUndefined(Address addr, int size) throws CodeUnitInsertionException {
MemoryBlock block = memory.getBlock(addr);
if (block == null) {
return null;
}
DataType undefined = Undefined.getUndefinedDataType(size);
return listing.createData(addr, undefined);
}
@Override
public Symbol createSymbol(Address addr, String name, boolean isPrimary, boolean pinAbsolute,
Namespace namespace) throws InvalidInputException {

View file

@ -609,6 +609,7 @@ The Headless Analyzer uses the command-line parameters discussed below. See <a h
<LI><typewriter>-loader-libraryLoadDepth &lt;depth&gt;</typewriter></LI>
<LI><typewriter>-loader-libraryDestinationFolder &lt;project path&gt;</typewriter></LI>
<LI><typewriter>-loader-applyRelocations &lt;true|false&gt;</typewriter></LI>
<LI><typewriter>-loader-applyUndefinedData &lt;true|false&gt;</typewriter></LI>
<LI><typewriter>-loader-imagebase &lt;imagebase<sup>3</sup>&gt;</typewriter></LI>
<LI><typewriter>-loader-dataImageBase &lt;dataImageBase<sup>4</sup>&gt;</typewriter></LI>
<LI><typewriter>-loader-includeOtherBlocks &lt;true|false&gt;</typewriter></LI>