diff --git a/Ghidra/Features/Base/src/main/help/help/topics/MemoryMapPlugin/Memory_Map.htm b/Ghidra/Features/Base/src/main/help/help/topics/MemoryMapPlugin/Memory_Map.htm
index 4122b8f3f6..14bc73febb 100644
--- a/Ghidra/Features/Base/src/main/help/help/topics/MemoryMapPlugin/Memory_Map.htm
+++ b/Ghidra/Features/Base/src/main/help/help/topics/MemoryMapPlugin/Memory_Map.htm
@@ -60,7 +60,7 @@
by importers. At this point in time there is no capability provided by the Memory Map provider to create a
new File Bytes instance.
- Overlay - Each of the above memory block types may optionally be specified as an Overlay at the
+
Overlay - Each of the above memory block types may optionally be specified as an Overlay at the
time of creation. If this option is selected, the block is created in a new
overlay address space. Overlay blocks can serve various
purposes where a memory range may contain different data/code or map to different areas of memory
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/DWARFAnalyzer.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/DWARFAnalyzer.java
index 9c10a8d872..45627bfbdf 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/DWARFAnalyzer.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/DWARFAnalyzer.java
@@ -27,6 +27,7 @@ import ghidra.app.util.importer.MessageLog;
import ghidra.framework.options.Options;
import ghidra.program.model.address.AddressSetView;
import ghidra.program.model.data.BuiltInDataTypeManager;
+import ghidra.program.model.lang.Language;
import ghidra.program.model.listing.Program;
import ghidra.util.Msg;
import ghidra.util.exception.CancelledException;
@@ -91,6 +92,15 @@ public class DWARFAnalyzer extends AbstractAnalyzer {
setSupportsOneTimeAnalysis();
}
+ @Override
+ public boolean getDefaultEnablement(Program program) {
+ // TODO: DWARF implementation needs improvements to handle Harvard Architectures properly
+ // Currently unable to produce addresses which should refer to data space resulting in
+ // improperly placed symbols, etc.
+ Language language = program.getLanguage();
+ return language.getDefaultSpace() == language.getDefaultDataSpace();
+ }
+
@Override
public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log)
throws CancelledException {
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/disassembler/EntryPointAnalyzer.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/disassembler/EntryPointAnalyzer.java
index 8fd8b4d85e..ff24aec6d4 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/disassembler/EntryPointAnalyzer.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/disassembler/EntryPointAnalyzer.java
@@ -443,7 +443,7 @@ public class EntryPointAnalyzer extends AbstractAnalyzer {
}
private boolean isLanguageDefinedEntry(Program program, Address addr) {
- List labelList = program.getLanguage().getDefaultLabels();
+ List labelList = program.getLanguage().getDefaultSymbols();
for (AddressLabelInfo info : labelList) {
if (addr.equals(info.getAddress())) {
return info.isEntry();
@@ -453,7 +453,7 @@ public class EntryPointAnalyzer extends AbstractAnalyzer {
}
private boolean isLanguageDefinedEntryPointer(Program program, Address addr) {
- List labelList = program.getLanguage().getDefaultLabels();
+ List labelList = program.getLanguage().getDefaultSymbols();
for (AddressLabelInfo info : labelList) {
if (addr.equals(info.getAddress())) {
ProcessorSymbolType type = info.getProcessorSymbolType();
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/ParamInfo.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/ParamInfo.java
index 481967b3d8..357b74d880 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/ParamInfo.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/ParamInfo.java
@@ -110,6 +110,9 @@ public class ParamInfo {
}
void setOrdinal(int i) {
+ if (original != null && original.getOrdinal() != i) {
+ original = null;
+ }
this.ordinal = i;
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/DIEAggregate.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/DIEAggregate.java
index 7eb530454e..7a160c2c9f 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/DIEAggregate.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/DIEAggregate.java
@@ -865,7 +865,7 @@ public class DIEAggregate {
// if the DWARF attr was a DW_FORM_addr, it doesn't need fixing up
if (high.form == DWARFForm.DW_FORM_addr) {
- return highVal.getUnsignedValue() + getProgram().getProgramBaseAddressFixup();
+ return highVal.getUnsignedValue() + getProgram().getProgramBaseAddressFixup() - 1;
}
// else it was a DW_FORM_data value and is relative to the lowPC value
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFFunctionImporter.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFFunctionImporter.java
index d271e08899..786da2b95c 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFFunctionImporter.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFFunctionImporter.java
@@ -605,7 +605,7 @@ public class DWARFFunctionImporter {
private final Address toAddr(Number offset) {
return currentProgram.getAddressFactory().getDefaultAddressSpace().getAddress(
- offset.longValue());
+ offset.longValue(), true);
}
/**
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfHeader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfHeader.java
index d3aca3a02b..4eaa5ecdb2 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfHeader.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/ElfHeader.java
@@ -630,12 +630,11 @@ public class ElfHeader implements StructConverter, Writeable {
}
ArrayList stringTableList = new ArrayList<>();
- for (int i = 0; i < sectionHeaders.length; ++i) {
- if (sectionHeaders[i].getType() == ElfSectionHeaderConstants.SHT_STRTAB) {
- ElfSectionHeader stringTableSectionHeader = sectionHeaders[i];
+ for (ElfSectionHeader stringTableSectionHeader : sectionHeaders) {
+ if (stringTableSectionHeader.getType() == ElfSectionHeaderConstants.SHT_STRTAB) {
ElfStringTable stringTable = ElfStringTable.createElfStringTable(reader, this,
stringTableSectionHeader, stringTableSectionHeader.getOffset(),
- sectionHeaders[i].getAddress(), stringTableSectionHeader.getSize());
+ stringTableSectionHeader.getAddress(), stringTableSectionHeader.getSize());
stringTableList.add(stringTable);
if (stringTable.getAddressOffset() == dynamicStringTableAddr) {
dynamicStringTable = stringTable;
@@ -703,10 +702,9 @@ public class ElfHeader implements StructConverter, Writeable {
// Add section based symbol tables
ArrayList symbolTableList = new ArrayList<>();
- for (int i = 0; i < sectionHeaders.length; ++i) {
- if (sectionHeaders[i].getType() == ElfSectionHeaderConstants.SHT_SYMTAB ||
- sectionHeaders[i].getType() == ElfSectionHeaderConstants.SHT_DYNSYM) {
- ElfSectionHeader symbolTableSectionHeader = sectionHeaders[i];
+ for (ElfSectionHeader symbolTableSectionHeader : sectionHeaders) {
+ if (symbolTableSectionHeader.getType() == ElfSectionHeaderConstants.SHT_SYMTAB ||
+ symbolTableSectionHeader.getType() == ElfSectionHeaderConstants.SHT_DYNSYM) {
if (symbolTableSectionHeader.getOffset() < 0) {
continue;
}
@@ -896,15 +894,15 @@ public class ElfHeader implements StructConverter, Writeable {
// HACK: 07/01/2013 - Added hack for malformed ELF file with only program header sections
ElfProgramHeader[] pheaders = getProgramHeaders();
long size = 0;
- for (int i = 0; i < pheaders.length; i++) {
- size += pheaders[i].getFileSize();
+ for (ElfProgramHeader pheader : pheaders) {
+ size += pheader.getFileSize();
}
if (size == fileLength) {
// adjust program section file offset to be based on relative read offset
long relOffset = 0;
- for (int i = 0; i < pheaders.length; i++) {
- pheaders[i].setOffset(relOffset);
- relOffset += pheaders[i].getFileSize();
+ for (ElfProgramHeader pheader : pheaders) {
+ pheader.setOffset(relOffset);
+ relOffset += pheader.getFileSize();
}
}
}
@@ -1322,9 +1320,9 @@ public class ElfHeader implements StructConverter, Writeable {
*/
public ElfSectionHeader[] getSections(int type) {
ArrayList list = new ArrayList<>();
- for (int i = 0; i < sectionHeaders.length; i++) {
- if (sectionHeaders[i].getType() == type) {
- list.add(sectionHeaders[i]);
+ for (ElfSectionHeader sectionHeader : sectionHeaders) {
+ if (sectionHeader.getType() == type) {
+ list.add(sectionHeader);
}
}
ElfSectionHeader[] sections = new ElfSectionHeader[list.size()];
@@ -1340,15 +1338,17 @@ public class ElfHeader implements StructConverter, Writeable {
*/
public ElfSectionHeader getSection(String name) {
List list = new ArrayList<>();
- for (int i = 0; i < sectionHeaders.length; i++) {
- if (name != null && name.equals(sectionHeaders[i].getNameAsString())) {
- list.add(sectionHeaders[i]);
+ for (ElfSectionHeader sectionHeader : sectionHeaders) {
+ if (name != null && name.equals(sectionHeader.getNameAsString())) {
+ list.add(sectionHeader);
}
}
- if (list.size() == 0)
+ if (list.size() == 0) {
return null;
- if (list.size() > 1)
+ }
+ if (list.size() > 1) {
throw new RuntimeException(">1 section with name of " + name);
+ }
return list.get(0);
}
@@ -1359,9 +1359,9 @@ public class ElfHeader implements StructConverter, Writeable {
* @return the section header with the specified address
*/
public ElfSectionHeader getSectionAt(long address) {
- for (int i = 0; i < sectionHeaders.length; i++) {
- if (sectionHeaders[i].getAddress() == address) {
- return sectionHeaders[i];
+ for (ElfSectionHeader sectionHeader : sectionHeaders) {
+ if (sectionHeader.getAddress() == address) {
+ return sectionHeader;
}
}
return null;
@@ -1375,14 +1375,14 @@ public class ElfHeader implements StructConverter, Writeable {
*/
public ElfSectionHeader getSectionLoadHeaderContaining(long address) {
// FIXME: verify
- for (int i = 0; i < sectionHeaders.length; i++) {
- if (!sectionHeaders[i].isAlloc()) {
+ for (ElfSectionHeader sectionHeader : sectionHeaders) {
+ if (!sectionHeader.isAlloc()) {
continue;
}
- long start = sectionHeaders[i].getAddress();
- long end = start + sectionHeaders[i].getSize();
+ long start = sectionHeader.getAddress();
+ long end = start + sectionHeader.getSize();
if (start <= address && address <= end) {
- return sectionHeaders[i];
+ return sectionHeader;
}
}
return null;
@@ -1447,9 +1447,9 @@ public class ElfHeader implements StructConverter, Writeable {
*/
public ElfProgramHeader[] getProgramHeaders(int type) {
ArrayList list = new ArrayList<>();
- for (int i = 0; i < programHeaders.length; i++) {
- if (programHeaders[i].getType() == type) {
- list.add(programHeaders[i]);
+ for (ElfProgramHeader programHeader : programHeaders) {
+ if (programHeader.getType() == type) {
+ list.add(programHeader);
}
}
ElfProgramHeader[] arr = new ElfProgramHeader[list.size()];
@@ -1487,9 +1487,9 @@ public class ElfHeader implements StructConverter, Writeable {
* @return the program header with the specified address
*/
public ElfProgramHeader getProgramHeaderAt(long virtualAddr) {
- for (int i = 0; i < programHeaders.length; i++) {
- if (programHeaders[i].getVirtualAddress() == virtualAddr) {
- return programHeaders[i];
+ for (ElfProgramHeader programHeader : programHeaders) {
+ if (programHeader.getVirtualAddress() == virtualAddr) {
+ return programHeader;
}
}
return null;
@@ -1502,15 +1502,15 @@ public class ElfHeader implements StructConverter, Writeable {
* @return the program header with the specified address
*/
public ElfProgramHeader getProgramLoadHeaderContaining(long virtualAddr) {
- for (int i = 0; i < programHeaders.length; i++) {
- if (programHeaders[i] == null ||
- programHeaders[i].getType() != ElfProgramHeaderConstants.PT_LOAD) {
+ for (ElfProgramHeader programHeader : programHeaders) {
+ if (programHeader == null ||
+ programHeader.getType() != ElfProgramHeaderConstants.PT_LOAD) {
continue;
}
- long start = programHeaders[i].getVirtualAddress();
- long end = programHeaders[i].getAdjustedMemorySize() - 1 + start;
+ long start = programHeader.getVirtualAddress();
+ long end = programHeader.getAdjustedMemorySize() - 1 + start;
if (virtualAddr >= start && virtualAddr <= end) {
- return programHeaders[i];
+ return programHeader;
}
}
return null;
@@ -1523,15 +1523,15 @@ public class ElfHeader implements StructConverter, Writeable {
* @return the program header with the specified file offset
*/
public ElfProgramHeader getProgramLoadHeaderContainingFileOffset(long offset) {
- for (int i = 0; i < programHeaders.length; i++) {
- if (programHeaders[i] == null ||
- programHeaders[i].getType() != ElfProgramHeaderConstants.PT_LOAD) {
+ for (ElfProgramHeader programHeader : programHeaders) {
+ if (programHeader == null ||
+ programHeader.getType() != ElfProgramHeaderConstants.PT_LOAD) {
continue;
}
- long start = programHeaders[i].getOffset();
- long end = start + (programHeaders[i].getFileSize() - 1);
+ long start = programHeader.getOffset();
+ long end = start + (programHeader.getFileSize() - 1);
if (offset >= start && offset <= end) {
- return programHeaders[i];
+ return programHeader;
}
}
return null;
@@ -1567,9 +1567,9 @@ public class ElfHeader implements StructConverter, Writeable {
* @return the string table associated to the specified section header
*/
public ElfStringTable getStringTable(ElfSectionHeader section) {
- for (int i = 0; i < stringTables.length; i++) {
- if (stringTables[i].getFileOffset() == section.getOffset()) {
- return stringTables[i];
+ for (ElfStringTable stringTable : stringTables) {
+ if (stringTable.getFileOffset() == section.getOffset()) {
+ return stringTable;
}
}
return null;
@@ -1600,9 +1600,9 @@ public class ElfHeader implements StructConverter, Writeable {
if (symbolTableSection == null) {
return null;
}
- for (int i = 0; i < symbolTables.length; i++) {
- if (symbolTables[i].getFileOffset() == symbolTableSection.getOffset()) {
- return symbolTables[i];
+ for (ElfSymbolTable symbolTable : symbolTables) {
+ if (symbolTable.getFileOffset() == symbolTableSection.getOffset()) {
+ return symbolTable;
}
}
return null;
@@ -1633,9 +1633,9 @@ public class ElfHeader implements StructConverter, Writeable {
* @return the relocation table located at the specified fileOffset or null
*/
public ElfRelocationTable getRelocationTableAtOffset(long fileOffset) {
- for (int i = 0; i < relocationTables.length; i++) {
- if (relocationTables[i].getFileOffset() == fileOffset) {
- return relocationTables[i];
+ for (ElfRelocationTable relocationTable : relocationTables) {
+ if (relocationTable.getFileOffset() == fileOffset) {
+ return relocationTable;
}
}
return null;
@@ -1707,7 +1707,7 @@ public class ElfHeader implements StructConverter, Writeable {
* @return e_entry component ordinal
*/
public int getEntryComponentOrdinal() {
- return 9;
+ return 11;
}
/**
@@ -1716,7 +1716,7 @@ public class ElfHeader implements StructConverter, Writeable {
* @return e_phoff component ordinal
*/
public int getPhoffComponentOrdinal() {
- return 10;
+ return 12;
}
/**
@@ -1725,7 +1725,7 @@ public class ElfHeader implements StructConverter, Writeable {
* @return e_shoff component ordinal
*/
public int getShoffComponentOrdinal() {
- return 11;
+ return 13;
}
private void addSection(ElfSectionHeader newSection) {
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/relocation/ElfRelocationContext.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/relocation/ElfRelocationContext.java
index 020c76ffd8..e11895122d 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/relocation/ElfRelocationContext.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/relocation/ElfRelocationContext.java
@@ -259,4 +259,14 @@ public class ElfRelocationContext {
}
}
+ /**
+ * Get relocation address
+ * @param baseAddress base address
+ * @param relocOffset relocation offset relative to baseAddress
+ * @return relocation address
+ */
+ public Address getRelocationAddress(Address baseAddress, long relocOffset) {
+ return baseAddress.addWrap(relocOffset);
+ }
+
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/AbstractProgramLoader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/AbstractProgramLoader.java
index 4e9b49c389..cd7c8fd959 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/AbstractProgramLoader.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/AbstractProgramLoader.java
@@ -179,7 +179,8 @@ public abstract class AbstractProgramLoader implements Loader {
public List getDefaultOptions(ByteProvider provider, LoadSpec loadSpec,
DomainObject domainObject, boolean isLoadIntoProgram) {
ArrayList list = new ArrayList<>();
- list.add(new Option(APPLY_LABELS_OPTION_NAME, shouldApplyProcessorLabelsByDefault(),
+ list.add(new Option(APPLY_LABELS_OPTION_NAME,
+ shouldApplyProcessorLabelsByDefault(),
Boolean.class, Loader.COMMAND_LINE_ARG_PREFIX + "-applyLabels"));
list.add(new Option(ANCHOR_LABELS_OPTION_NAME, true, Boolean.class,
Loader.COMMAND_LINE_ARG_PREFIX + "-anchorLabels"));
@@ -404,50 +405,23 @@ public abstract class AbstractProgramLoader implements Loader {
private void applyProcessorLabels(List options, Program program) {
int id = program.startTransaction("Finalize load");
try {
+ Language lang = program.getLanguage();
+ // always create anchored symbols for memory mapped registers
+ // which may be explicitly referenced by pcode
+ for (Register reg : lang.getRegisters()) {
+ Address addr = reg.getAddress();
+ if (addr.isMemoryAddress()) {
+ AddressLabelInfo info = new AddressLabelInfo(addr, reg.getName(),
+ reg.isBaseRegister(), SourceType.IMPORTED);
+ createSymbol(program, info, true);
+ }
+ }
+ // optionally create default symbols defined by pspec
if (shouldApplyProcessorLabels(options)) {
boolean anchorSymbols = shouldAnchorSymbols(options);
- Language lang = program.getLanguage();
- SymbolTable symTable = program.getSymbolTable();
-
- List labels = lang.getDefaultLabels();
+ List labels = lang.getDefaultSymbols();
for (AddressLabelInfo info : labels) {
- Address addr = info.getAddress();
- Symbol s = symTable.getPrimarySymbol(addr);
- try {
- if (s == null || s.getSource() == SourceType.IMPORTED) {
- Namespace namespace = program.getGlobalNamespace();
- if (info.getScope() != null) {
- namespace = info.getScope();
- }
- s = symTable.createLabel(addr, info.getLabel(), namespace,
- info.getSource());
- if (info.isEntry()) {
- symTable.addExternalEntryPoint(addr);
- }
- if (info.isPrimary()) {
- s.setPrimary();
- }
- if (anchorSymbols) {
- s.setPinned(true);
- }
- }
- else if (s.getSource() == SourceType.DEFAULT) {
- String labelName = info.getLabel();
- if (s.getSymbolType() == SymbolType.FUNCTION) {
- Function f = (Function) s.getObject();
- f.setName(labelName, SourceType.IMPORTED);
- }
- else {
- s.setName(labelName, SourceType.IMPORTED);
- }
- if (anchorSymbols) {
- s.setPinned(true);
- }
- }
- }
- catch (DuplicateNameException | InvalidInputException e) {
- // Nothing to do
- }
+ createSymbol(program, info, anchorSymbols);
}
}
GhidraProgramUtilities.removeAnalyzedFlag(program);
@@ -457,6 +431,47 @@ public abstract class AbstractProgramLoader implements Loader {
}
}
+ private void createSymbol(Program program, AddressLabelInfo info, boolean anchorSymbols) {
+ SymbolTable symTable = program.getSymbolTable();
+ Address addr = info.getAddress();
+ Symbol s = symTable.getPrimarySymbol(addr);
+ try {
+ if (s == null || s.getSource() == SourceType.IMPORTED) {
+ Namespace namespace = program.getGlobalNamespace();
+ if (info.getScope() != null) {
+ namespace = info.getScope();
+ }
+ s = symTable.createLabel(addr, info.getLabel(), namespace,
+ info.getSource());
+ if (info.isEntry()) {
+ symTable.addExternalEntryPoint(addr);
+ }
+ if (info.isPrimary()) {
+ s.setPrimary();
+ }
+ if (anchorSymbols) {
+ s.setPinned(true);
+ }
+ }
+ else if (s.getSource() == SourceType.DEFAULT) {
+ String labelName = info.getLabel();
+ if (s.getSymbolType() == SymbolType.FUNCTION) {
+ Function f = (Function) s.getObject();
+ f.setName(labelName, SourceType.IMPORTED);
+ }
+ else {
+ s.setName(labelName, SourceType.IMPORTED);
+ }
+ if (anchorSymbols) {
+ s.setPinned(true);
+ }
+ }
+ }
+ catch (DuplicateNameException | InvalidInputException e) {
+ // Nothing to do
+ }
+ }
+
private String computeBinaryMD5(ByteProvider provider) throws IOException {
try (InputStream in = provider.getInputStream(0)) {
return MD5Utilities.getMD5Hash(in);
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/ElfLoaderOptionsFactory.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/ElfLoaderOptionsFactory.java
index 5ebea5efa7..9fe094e5a0 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/ElfLoaderOptionsFactory.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/ElfLoaderOptionsFactory.java
@@ -23,9 +23,8 @@ import ghidra.app.util.OptionUtils;
import ghidra.app.util.bin.ByteProvider;
import ghidra.app.util.bin.format.elf.ElfException;
import ghidra.app.util.bin.format.elf.ElfHeader;
-import ghidra.program.model.address.AddressOutOfBoundsException;
-import ghidra.program.model.address.AddressSpace;
-import ghidra.program.model.lang.LanguageNotFoundException;
+import ghidra.program.model.address.*;
+import ghidra.program.model.lang.*;
import ghidra.util.NumericUtilities;
import ghidra.util.StringUtilities;
@@ -41,6 +40,8 @@ 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
static final boolean INCLUDE_OTHER_BLOCKS_DEFAULT = true;
@@ -66,12 +67,20 @@ public class ElfLoaderOptionsFactory {
if (imageBase == 0 && (elf.isRelocatable() || elf.isSharedObject())) {
imageBase = elf.is64Bit() ? IMAGE64_BASE_DEFAULT : IMAGE_BASE_DEFAULT;
}
- AddressSpace defaultSpace =
- loadSpec.getLanguageCompilerSpec().getLanguage().getDefaultSpace();
+ Language language = loadSpec.getLanguageCompilerSpec().getLanguage();
+ AddressSpace defaultSpace = language.getDefaultSpace();
- String baseOffsetStr = getBaseOffsetString(imageBase, defaultSpace);
- options.add(new Option(IMAGE_BASE_OPTION_NAME, baseOffsetStr, String.class,
+ 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 =
+ getBaseAddressOffsetString(minDataImageBase, language.getDefaultDataSpace());
+ options.add(new Option(IMAGE_DATA_IMAGE_BASE_OPTION_NAME, hexValueStr, String.class,
+ Loader.COMMAND_LINE_ARG_PREFIX + "-dataImageBase"));
+ }
options.add(new Option(INCLUDE_OTHER_BLOCKS, INCLUDE_OTHER_BLOCKS_DEFAULT, Boolean.class,
Loader.COMMAND_LINE_ARG_PREFIX + "-includeOtherBlocks"));
@@ -80,14 +89,56 @@ public class ElfLoaderOptionsFactory {
new Option(RESOLVE_EXTERNAL_SYMBOLS_OPTION_NAME, RESOLVE_EXTERNAL_SYMBOLS_DEFAULT,
Boolean.class, Loader.COMMAND_LINE_ARG_PREFIX + "-resolveExternalSymbols"));
}
+
+ private static boolean includeDataImageBaseOption(ElfHeader elf, Language language) {
+ // only include option if all segments and section have a 0 address
+ AddressSpace defaultSpace = language.getDefaultSpace();
+ AddressSpace defaultDataSpace = language.getDefaultDataSpace();
+ if (defaultDataSpace.equals(defaultSpace)) {
+ return false;
+ }
+ 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()) {
+ Address addr = reg.getAddress();
+ if (defaultDataSpace.equals(addr.getAddressSpace())) {
+ long offset = addr.getOffset();
+ if (offset < 0) {
+ continue;
+ }
+ offset += reg.getMinimumByteSize();
+ if (offset > minOffset) {
+ minOffset = offset;
+ }
+ }
+ }
+ // set minimum align
+ int align = 16 * unitSize;
+ minOffset += align - (minOffset % align);
+ return minOffset / unitSize;
+ }
- private static String getBaseOffsetString(long imageBase, AddressSpace defaultSpace) {
- long maxOffset = defaultSpace.getMaxAddress().getAddressableWordOffset();
+ private static String getBaseAddressOffsetString(long imageBase, AddressSpace space) {
+ long maxOffset = space.getMaxAddress().getAddressableWordOffset();
while (Long.compareUnsigned(imageBase, maxOffset) > 0) {
imageBase >>>= 4;
}
String baseOffsetStr = Long.toHexString(imageBase);
- int minNibbles = Math.min(8, defaultSpace.getSize() / 4);
+ int minNibbles = Math.min(8, space.getSize() / 4);
int baseOffsetStrLen = baseOffsetStr.length();
if (baseOffsetStrLen < minNibbles) {
baseOffsetStr =
@@ -97,6 +148,12 @@ public class ElfLoaderOptionsFactory {
}
static String validateOptions(LoadSpec loadSpec, List options) {
+ Language language;
+ try {
+ language = loadSpec.getLanguageCompilerSpec().getLanguage();
+ } catch (LanguageNotFoundException e) {
+ throw new RuntimeException(e);
+ }
for (Option option : options) {
String name = option.getName();
if (name.equals(PERFORM_RELOCATIONS_NAME)) {
@@ -110,25 +167,29 @@ public class ElfLoaderOptionsFactory {
}
}
else if (name.equals(IMAGE_BASE_OPTION_NAME)) {
- if (!String.class.isAssignableFrom(option.getValueClass())) {
- return "Invalid type for option: " + name + " - " + option.getValueClass();
- }
- String value = (String) option.getValue();
- try {
- AddressSpace space =
- loadSpec.getLanguageCompilerSpec().getLanguage().getDefaultSpace();
- space.getAddress(Long.parseUnsignedLong(value, 16));// verify valid address
- }
- catch (NumberFormatException e) {
- return "Invalid " + name + " - expecting hexidecimal address offset";
- }
- catch (AddressOutOfBoundsException e) {
- return "Invalid " + name + " - " + e.getMessage();
- }
- catch (LanguageNotFoundException e) {
- throw new RuntimeException(e);
- }
+ return validateAddressSpaceOffsetOption(option, language.getDefaultSpace());
}
+ else if (name.equals(IMAGE_DATA_IMAGE_BASE_OPTION_NAME)) {
+ return validateAddressSpaceOffsetOption(option, language.getDefaultDataSpace());
+ }
+ }
+ return null;
+ }
+
+ private static String validateAddressSpaceOffsetOption(Option option, AddressSpace space) {
+ String name = option.getName();
+ if (!String.class.isAssignableFrom(option.getValueClass())) {
+ return "Invalid type for option: " + name + " - " + option.getValueClass();
+ }
+ String value = (String) option.getValue();
+ try {
+ space.getAddress(Long.parseUnsignedLong(value, 16), true);// verify valid address
+ }
+ catch (NumberFormatException e) {
+ return "Invalid " + name + " - expecting hexidecimal address offset";
+ }
+ catch (AddressOutOfBoundsException e) {
+ return "Invalid " + name + " - " + e.getMessage();
}
return null;
}
@@ -149,4 +210,9 @@ public class ElfLoaderOptionsFactory {
public static String getImageBaseOption(List options) {
return OptionUtils.getOption(IMAGE_BASE_OPTION_NAME, options, (String) null);
}
+
+ public static String getDataImageBaseOption(List options) {
+ return OptionUtils.getOption(IMAGE_DATA_IMAGE_BASE_OPTION_NAME, options, (String) null);
+ }
+
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/ElfProgramBuilder.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/ElfProgramBuilder.java
index bdc2418c59..79c4024c68 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/ElfProgramBuilder.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/ElfProgramBuilder.java
@@ -19,8 +19,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.text.NumberFormat;
-import java.util.HashMap;
-import java.util.List;
+import java.util.*;
import java.util.function.Consumer;
import ghidra.app.cmd.label.SetLabelPrimaryCmd;
@@ -69,6 +68,7 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
private static final int DISCARDABLE_SEGMENT_SIZE = 0xff;
private List options;
+ private Long dataImageBase; // cached data image base option or null if not applicable
private MessageLog log;
private ElfHeader elf;
@@ -249,6 +249,17 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
Msg.error(this, "Can't set image base.", e);
}
}
+
+ private long getImageDataBase() {
+ if (dataImageBase == null) {
+ dataImageBase = 0L;
+ String imageBaseStr = ElfLoaderOptionsFactory.getDataImageBaseOption(options);
+ if (imageBaseStr != null) {
+ dataImageBase = NumericUtilities.parseHexLong(imageBaseStr);
+ }
+ }
+ return dataImageBase;
+ }
private void addProgramProperties(TaskMonitor monitor) throws CancelledException {
@@ -709,7 +720,7 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
}
private void processRelocationTable(ElfRelocationTable relocationTable,
- ElfRelocationContext context, AddressSpace relocationSpace, long baseOffset,
+ ElfRelocationContext context, AddressSpace relocationSpace, long baseWordOffset,
TaskMonitor monitor) throws CancelledException {
ElfSymbol[] symbols = relocationTable.getAssociatedSymbolTable().getSymbols();
@@ -725,8 +736,11 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
symbolName = symbols[symbolIndex].getNameAsString();
}
- long relocationOffset = baseOffset + reloc.getOffset();
- Address relocAddr = relocationSpace.getTruncatedAddress(relocationOffset, true);
+ Address baseAddress = relocationSpace.getTruncatedAddress(baseWordOffset, true);
+// long relocationOffset = baseWordOffset + reloc.getOffset();
+ // r_offset is defined to be a byte offset (assume byte size is 1)
+ Address relocAddr = context != null ? context.getRelocationAddress(baseAddress, reloc.getOffset()) : baseAddress.addWrap(reloc.getOffset());;
+// Address relocAddr = relocationSpace.getTruncatedAddress(relocationOffset, true);
long[] values = new long[] { reloc.getSymbolIndex() };
@@ -1261,6 +1275,7 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
short sectionIndex = elfSymbol.getSectionHeaderIndex();
Address symSectionBase = null;
AddressSpace defaultSpace = getDefaultAddressSpace();
+ AddressSpace defaultDataSpace = getDefaultDataSpace();
AddressSpace symbolSpace = defaultSpace;
long symOffset = elfSymbol.getValue();
@@ -1276,11 +1291,14 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
return null;
}
symbolSpace = symSectionBase.getAddressSpace();
- } // else assume sections have been stripped - always use default space
+ } // else assume sections have been stripped
if (symbolSpace.getPhysicalSpace() == defaultSpace) {
symOffset =
elf.adjustAddressForPrelink(symOffset) + getImageBaseWordAdjustmentOffset();
}
+ else if (symbolSpace.getPhysicalSpace() == defaultDataSpace) {
+ symOffset += getImageDataBase();
+ }
}
else if (sectionIndex == ElfSectionHeaderConstants.SHN_UNDEF) { // Not section relative 0x0000 (e.g., no sections defined)
// FIXME: No sections defined or refers to external symbol
@@ -1288,10 +1306,8 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
// EXTERNAL block is affected by the program image base
symOffset += getImageBaseWordAdjustmentOffset();
}
-//FIXME! We are not handling absolute and common symbols properly
-//Should constants be placed in constant space?
else if (sectionIndex == ElfSectionHeaderConstants.SHN_ABS) { // Absolute value/address - 0xfff1
- // TODO: Which space ? Can't distinguish data vs. code/default space
+ // TODO: Which space ? Can't distinguish simple constant vs. data vs. code/default space
// The should potentially be assign a constant address instead (not possible currently)
// Note: Assume data space - symbols will be "pinned"
@@ -2463,24 +2479,18 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
}
}
- /**
- * Process the program headers and their loaded segments many of which are normally
- * loaded through the section headers.
- * This is probably not the correct thing to do unless you have a munged ELF
- * @param maintainExecuteBit
- * @throws CancelledException
- *
- */
private void processProgramHeaders(TaskMonitor monitor) throws CancelledException {
+
+ if (elf.isRelocatable() && elf.e_phnum() != 0) {
+ log("Ignoring unexpected program headers for relocatable ELF (e_phnum=" +
+ elf.e_phnum() + ")");
+ return;
+ }
+
monitor.setMessage("Processing program headers...");
boolean includeOtherBlocks = ElfLoaderOptionsFactory.includeOtherBlocks(options);
- // TODO: Use of nextRelocStart only works within default space
- // and cause problems if used within data space - we may need to devise
- // a better approach to allocating load addresses
- long nextRelocStart = elf.getImageBase();
-
ElfProgramHeader[] elfProgramHeaders = elf.getProgramHeaders();
for (int i = 0; i < elfProgramHeaders.length; ++i) {
monitor.checkCanceled();
@@ -2514,16 +2524,22 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
"] with invalid file offset");
continue;
}
- nextRelocStart = processProgramHeader(elfProgramHeader, nextRelocStart, i, monitor);
+ processProgramHeader(elfProgramHeader, i);
}
}
- private long processProgramHeader(ElfProgramHeader elfProgramHeader, long relocStart,
- int segmentNumber, TaskMonitor monitor) throws AddressOutOfBoundsException {
+ /**
+ * Process the specified program header by ensuring that it has a suitable memory address assigned
+ * and added to the memory resolver.
+ * @param elfProgramHeader ELF program header to be processed
+ * @param segmentNumber program header index number
+ * @throws AddressOutOfBoundsException if an invalid memory address is encountered
+ */
+ private void processProgramHeader(
+ ElfProgramHeader elfProgramHeader,
+ int segmentNumber) throws AddressOutOfBoundsException {
-// FIXME: the relocStart concept does not properly consider multiple address spaces
-
-// FIXME: If physical and virtual addresses do not match this may be an overlay situation
+// FIXME: If physical and virtual addresses do not match this may be an overlay situation.
// If sections exist they should use file offsets to correlate to overlay segment - the
// problem is that we can only handle a single memory block per overlay range - we may need to
// not load segment in this case and defer to section!! Such situations may also
@@ -2543,30 +2559,13 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
if (fullSizeBytes <= 0) {
log("Skipping zero-length segment [" + segmentNumber + "," +
elfProgramHeader.getDescription() + "] at address " + address.toString(true));
- return relocStart;
+ return;
}
-
- // In a relocatable ELF, the address of all sections is zero.
- // Therefore, we shall manufacture an arbitrary address that
- // will pack the sections together. (may not work with separate Data space!)
- long nextRelocStart = relocStart;
- if (elf.isRelocatable() && addr == 0 && fullSizeBytes != 0) {
- log("Relocatable segment [" + segmentNumber + "] assigned address " +
- address.toString(true));
- // TODO: Use of nextRelocStart only works within default space
- // and cause problems if used within data space - we may need to devise
- // a better approach to allocating load addresses
- long vaddr = addr;
- addr = nextRelocStart; // TODO: Force proper alignment
- address = address.getNewAddress(nextRelocStart, true);
- elfProgramHeader.setAddress(addr, vaddr);
- nextRelocStart += fullSizeBytes / space.getAddressableUnitSize();
- }
-
+
if (!space.isValidRange(address.getOffset(), fullSizeBytes)) {
log("Skipping unloadable segment [" + segmentNumber + "] at address " +
address.toString(true) + " (size=" + fullSizeBytes + ")");
- return relocStart;
+ return;
}
try {
@@ -2596,7 +2595,6 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
catch (AddressOverflowException e) {
log("Failed to load segment [" + segmentNumber + "]: " + getMessage(e));
}
- return nextRelocStart;
}
private String getSectionComment(long addr, long byteSize, int addressableUnitSize,
@@ -2653,10 +2651,12 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
* When an image is relocatable generally all sections will have a zero address. It is only
* when special sections are present (e.g., __ksymtab) that we may encounter sections with
* a non-zero address.
- * @param monitor
+ * @param monitor task monitor
* @return start of relocation area
+ * @throws CancelledException task cancelled
*/
- private long computeRelocationStartAddress(TaskMonitor monitor) {
+ private long computeRelocationStartAddress(AddressSpace space, long baseOffset,
+ TaskMonitor monitor) throws CancelledException {
if (!elf.isRelocatable()) {
return 0; // not applicable
}
@@ -2664,9 +2664,7 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
AddressSpace defaultSpace = getDefaultAddressSpace();
ElfSectionHeader[] sections = elf.getSections();
for (ElfSectionHeader elfSectionToLoad : sections) {
- if (monitor.isCancelled()) {
- return 0;
- }
+ monitor.checkCanceled();
long addr = elfSectionToLoad.getAddress();
if (addr < 0) {
relocStartAddr = 0;
@@ -2674,9 +2672,9 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
}
if (elfSectionToLoad.isAlloc() && addr != 0) {
AddressSpace loadSpace = getSectionAddressSpace(elfSectionToLoad);
- if (loadSpace.equals(defaultSpace)) {
+ if (loadSpace.equals(space)) {
long sectionByteLength = elfSectionToLoad.getAdjustedSize(); // size in bytes
- long sectionLength = sectionByteLength / defaultSpace.getAddressableUnitSize();
+ long sectionLength = sectionByteLength / space.getAddressableUnitSize();
relocStartAddr = Math.max(relocStartAddr, addr + sectionLength);
}
}
@@ -2687,26 +2685,23 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
if (testOffset != defaultSpace.getTruncatedAddress(testOffset, true).getOffset()) {
relocStartAddr = 0;
}
-
- return relocStartAddr + elf.getImageBase();
+ return relocStartAddr + baseOffset;
}
- private void processSectionHeaders(TaskMonitor monitor) {
+ private void processSectionHeaders(TaskMonitor monitor) throws CancelledException {
monitor.setMessage("Processing section headers...");
boolean includeOtherBlocks = ElfLoaderOptionsFactory.includeOtherBlocks(options);
-
- // TODO: Use of nextRelocStart only works within default space
- // and cause problems if used within data space - we may need to devise
- // a better approach to allocating load addresses
- long nextRelocStart = computeRelocationStartAddress(monitor);
-
+
+ // establish section address provider for relocatable ELF binaries
+ RelocatableImageBaseProvider relocatableImageBaseProvider = null;
+ if (elf.isRelocatable()) {
+ relocatableImageBaseProvider = new RelocatableImageBaseProvider(monitor);
+ }
+
ElfSectionHeader[] sections = elf.getSections();
- for (int i = 0; i < sections.length; ++i) {
- if (monitor.isCancelled()) {
- return;
- }
- ElfSectionHeader elfSectionToLoad = sections[i];
+ for (ElfSectionHeader elfSectionToLoad : sections) {
+ monitor.checkCanceled();
if (elfSectionToLoad.getType() != ElfSectionHeaderConstants.SHN_UNDEF &&
(includeOtherBlocks || elfSectionToLoad.isAlloc())) {
long fileOffset = elfSectionToLoad.getOffset();
@@ -2715,34 +2710,48 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
"] with invalid file offset");
continue;
}
- nextRelocStart = processSectionHeader(elfSectionToLoad, i, nextRelocStart, monitor);
+ long size = elfSectionToLoad.getSize();
+ if (size <= 0 || size >= fileBytes.getSize()) {
+ log("Skipping section [" + elfSectionToLoad.getNameAsString() +
+ "] with invalid size");
+ continue;
+ }
+ processSectionHeader(elfSectionToLoad, relocatableImageBaseProvider);
}
}
}
- private long processSectionHeader(ElfSectionHeader elfSectionToLoad, int index, long relocStart,
- TaskMonitor monitor) throws AddressOutOfBoundsException {
+ /**
+ * Process the specified section header by ensuring that it has a suitable memory address assigned
+ * and added to the memory resolver.
+ * @param elfSectionToLoad ELF section header to be processed
+ * @param relocatableImageBaseProvider section address provider for relocatable ELF binaries.
+ * @throws AddressOutOfBoundsException if an invalid memory address is encountered
+ */
+ private void processSectionHeader(ElfSectionHeader elfSectionToLoad,
+ RelocatableImageBaseProvider relocatableImageBaseProvider)
+ throws AddressOutOfBoundsException {
long addr = elfSectionToLoad.getAddress();
long sectionByteLength = elfSectionToLoad.getAdjustedSize(); // size in bytes
long loadOffset = elfSectionToLoad.getOffset(); // file offset in bytes
+ Long nextRelocOffset = null;
- // TODO: if addr!=0, create section symbol (allows non loaded section to have some presence)
-
- long nextRelocStart = relocStart;
-
- // In a relocatable ELF, the address of all sections is zero.
- // Therefore, we shall manufacture an arbitrary address that
- // will pack the sections together.
+ // In a relocatable ELF (object module), the address of all sections is zero.
+ // Therefore, we shall assign an arbitrary address that
+ // will pack the sections together with proper alignment.
+
if (elfSectionToLoad.isAlloc() && elf.isRelocatable() && addr == 0) {
- // TODO: Use of nextRelocStart only works within default space
- // and cause problems if used within data space - we may need to devise
- // a better approach to allocating load addresses
- addr = NumericUtilities.getUnsignedAlignedValue(nextRelocStart,
+ // TODO: if program headers are present (very unlikely for object module)
+ // they should be used to determine section load address since they would
+ // be assigned first.
+ AddressSpace space = getSectionAddressSpace(elfSectionToLoad);
+ long relocOffset = relocatableImageBaseProvider.getNextRelocatableOffset(space);
+ addr = NumericUtilities.getUnsignedAlignedValue(
+ relocOffset,
elfSectionToLoad.getAddressAlignment());
elfSectionToLoad.setAddress(addr);
- nextRelocStart =
- addr + (sectionByteLength / getDefaultAddressSpace().getAddressableUnitSize());
+ nextRelocOffset = addr + (sectionByteLength / space.getAddressableUnitSize());
}
Address address = null;
@@ -2752,6 +2761,7 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
// Check for and consume uninitialized portion of PT_LOAD segment if possible
ElfProgramHeader loadHeader = elf.getProgramLoadHeaderContaining(addr);
if (loadHeader != null) {
+ // NOTE: should never apply to relocatable ELF
Address segmentStart = getSegmentLoadAddress(loadHeader);
AddressSpace segmentSpace = segmentStart.getAddressSpace();
long loadSizeBytes = loadHeader.getAdjustedLoadSize();
@@ -2772,7 +2782,7 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
if (sectionByteLength == 0) {
log("Skipping empty section [" + elfSectionToLoad.getNameAsString() + "]");
- return relocStart;
+ return;
}
if (address == null) {
@@ -2783,7 +2793,7 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
if (!space.isValidRange(address.getOffset(), sectionByteLength)) {
log("Skipping unloadable section [" + elfSectionToLoad.getNameAsString() +
"] at address " + address.toString(true) + " (size=" + sectionByteLength + ")");
- return relocStart;
+ return;
}
final String blockName = elfSectionToLoad.getNameAsString();
@@ -2793,7 +2803,7 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
elfSectionToLoad.getType() == ElfSectionHeaderConstants.SHT_NOBITS) {
if (!elfSectionToLoad.isAlloc() &&
elfSectionToLoad.getType() != ElfSectionHeaderConstants.SHT_PROGBITS) {
- return nextRelocStart; // non-allocate at runtime
+ return; // non-allocate at runtime
}
String comment =
getSectionComment(addr, sectionByteLength, space.getAddressableUnitSize(),
@@ -2815,8 +2825,10 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
log("Failed to load section [" + elfSectionToLoad.getNameAsString() + "]: " +
getMessage(e));
}
-
- return nextRelocStart;
+
+ if (nextRelocOffset != null) {
+ relocatableImageBaseProvider.setNextRelocatableOffset(space, nextRelocOffset);
+ }
}
private String pad(int value) {
@@ -3009,4 +3021,32 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
revisedLength, comment, BLOCK_SOURCE_NAME, r, w, x, log);
}
+ private class RelocatableImageBaseProvider {
+
+ Map nextRelocationOffsetMap = new HashMap<>();
+
+ RelocatableImageBaseProvider(TaskMonitor monitor) throws CancelledException {
+ AddressSpace defaultSpace = getDefaultAddressSpace();
+ AddressSpace defaultDataSpace = getDefaultDataSpace();
+ long baseOffset = computeRelocationStartAddress(defaultSpace, elf.getImageBase(), monitor);
+ nextRelocationOffsetMap.put(defaultSpace.getUnique(), baseOffset);
+ if (defaultDataSpace != defaultSpace) {
+ baseOffset = computeRelocationStartAddress(defaultDataSpace, getImageDataBase(), monitor);
+ nextRelocationOffsetMap.put(defaultDataSpace.getUnique(), baseOffset);
+ }
+ // In the future, an extension could introduce additional space entries
+ }
+
+ void setNextRelocatableOffset(AddressSpace space, Long nextRelocOffset) {
+ int unique = space.getUnique();
+ nextRelocationOffsetMap.put(unique, nextRelocOffset);
+ }
+
+ long getNextRelocatableOffset(AddressSpace space) {
+ int unique = space.getUnique();
+ Long nextRelocOffset = nextRelocationOffsetMap.get(unique);
+ return nextRelocOffset == null ? 0 : nextRelocOffset;
+ }
+ }
+
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/plugin/importer/ImporterDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/plugin/importer/ImporterDialog.java
index d6055b16c1..371292418a 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/plugin/importer/ImporterDialog.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/plugin/importer/ImporterDialog.java
@@ -563,12 +563,16 @@ public class ImporterDialog extends DialogComponentProvider {
}
private LanguageCompilerSpecPair getPreferredLanguage(Loader loader) {
+ LanguageCompilerSpecPair preferredSpecPair = null;
for (LoadSpec loadSpec : loaderMap.get(loader)) {
if (loadSpec.isPreferred()) {
- return loadSpec.getLanguageCompilerSpec();
+ if (preferredSpecPair != null) {
+ return null;
+ }
+ preferredSpecPair = loadSpec.getLanguageCompilerSpec();
}
}
- return null;
+ return preferredSpecPair;
}
private DomainFolder getProjectRootFolder() {
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/SleighLanguage.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/SleighLanguage.java
index 2b746298c4..5c514cd70b 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/SleighLanguage.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/SleighLanguage.java
@@ -265,22 +265,6 @@ public class SleighLanguage implements Language {
return getRegisterManager().getContextBaseRegister();
}
- @Override
- public List getDefaultLabels() {
- ArrayList list = new ArrayList<>();
-
- Register regs[] = getRegisters();
- for (Register reg : regs) {
- if (reg.getAddressSpace().isMemorySpace()) {
- AddressLabelInfo entry = new AddressLabelInfo(reg.getAddress(), reg.getName(), true,
- SourceType.IMPORTED);
- list.add(entry);
- }
- }
- list.addAll(getDefaultSymbols());
- return list;
- }
-
@Override
public MemoryBlockDefinition[] getDefaultMemoryBlocks() {
return defaultMemoryBlocks;
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/GhidraLanguagePropertyKeys.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/GhidraLanguagePropertyKeys.java
index a28f03678f..df76867542 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/GhidraLanguagePropertyKeys.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/GhidraLanguagePropertyKeys.java
@@ -119,4 +119,15 @@ public final class GhidraLanguagePropertyKeys {
* NOTE: This is an experimental concept which may be removed in the future
*/
public static final String RESET_CONTEXT_ON_UPGRADE = "resetContextOnUpgrade";
+
+ /**
+ * Property to indicate the minimum recommended base address within the default
+ * data space for placing relocatable data sections. This is intended to
+ * avoid loading into low memory regions where registers may be defined.
+ * The default value for ELF will be just beyond the last memory register defined
+ * within the default data space. This option is only utilized by the
+ * ELF Loader for Harvard Architecures when loading a relocatable ELF binary
+ * (i.e., object module) and corresponds to the ELF Loader option: Data Image Base.
+ */
+ public static final String MINIMUM_DATA_IMAGE_BASE = "minimumDataImageBase";
}
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/Language.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/Language.java
index 845fbc7108..85a7f921c4 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/Language.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/Language.java
@@ -226,13 +226,6 @@ public interface Language {
*/
public Register getRegister(Address addr, int size);
- /**
- * Return the list of labels for well-known locations.
- *
- * @return AddressLabelPair[] empty array if there are no labels
- */
- public List getDefaultLabels();
-
/**
* Get the default program counter register for this language if there is
* one.
@@ -254,7 +247,8 @@ public interface Language {
public MemoryBlockDefinition[] getDefaultMemoryBlocks();
/**
- * Returns the default symbols for this language.
+ * Returns the default symbols for this language. This list does not
+ * contain registers.
* @return the default symbols for this language
*/
public List getDefaultSymbols();
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/util/OldLanguage.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/util/OldLanguage.java
index b1ea11b821..394e960407 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/util/OldLanguage.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/util/OldLanguage.java
@@ -585,11 +585,6 @@ class OldLanguage implements Language {
return null;
}
- @Override
- public List getDefaultLabels() {
- throw new UnsupportedOperationException("Language for upgrade use only (getDefaultLabels)");
- }
-
@Override
public Register getProgramCounter() {
throw new UnsupportedOperationException(
diff --git a/Ghidra/Processors/PIC/certification.manifest b/Ghidra/Processors/PIC/certification.manifest
index 79fe4bb3a9..02c390faf2 100644
--- a/Ghidra/Processors/PIC/certification.manifest
+++ b/Ghidra/Processors/PIC/certification.manifest
@@ -9,6 +9,8 @@ data/languages/PIC24.sinc||GHIDRA||||END|
data/languages/PIC24E.slaspec||GHIDRA||reviewed||END|
data/languages/PIC24F.slaspec||GHIDRA||reviewed||END|
data/languages/PIC24H.slaspec||GHIDRA||reviewed||END|
+data/languages/PIC30.dwarf||GHIDRA||||END|
+data/languages/PIC33.dwarf||GHIDRA||||END|
data/languages/dsPIC30F.slaspec||GHIDRA||reviewed||END|
data/languages/dsPIC33C.slaspec||GHIDRA||||END|
data/languages/dsPIC33E.slaspec||GHIDRA||reviewed||END|
diff --git a/Ghidra/Processors/PIC/data/languages/PIC24.ldefs b/Ghidra/Processors/PIC/data/languages/PIC24.ldefs
index f423c5d4e0..72c7a948ba 100644
--- a/Ghidra/Processors/PIC/data/languages/PIC24.ldefs
+++ b/Ghidra/Processors/PIC/data/languages/PIC24.ldefs
@@ -48,6 +48,7 @@
id="dsPIC30F:LE:24:default">
dsPIC30F
+
dsPIC33F
+
dsPIC33E
+
dsPIC33C
+
diff --git a/Ghidra/Processors/PIC/data/languages/PIC24.opinion b/Ghidra/Processors/PIC/data/languages/PIC24.opinion
index 2c6a8df4bb..e96a02563d 100644
--- a/Ghidra/Processors/PIC/data/languages/PIC24.opinion
+++ b/Ghidra/Processors/PIC/data/languages/PIC24.opinion
@@ -4,7 +4,10 @@
-
+
+
+
+
diff --git a/Ghidra/Processors/PIC/data/languages/PIC24.pspec b/Ghidra/Processors/PIC/data/languages/PIC24.pspec
index 2a65a73d52..e08697bfc1 100644
--- a/Ghidra/Processors/PIC/data/languages/PIC24.pspec
+++ b/Ghidra/Processors/PIC/data/languages/PIC24.pspec
@@ -3,8 +3,8 @@
-
+
+
diff --git a/Ghidra/Processors/PIC/data/languages/PIC24.sinc b/Ghidra/Processors/PIC/data/languages/PIC24.sinc
index 51ee135876..5392c6e1c7 100644
--- a/Ghidra/Processors/PIC/data/languages/PIC24.sinc
+++ b/Ghidra/Processors/PIC/data/languages/PIC24.sinc
@@ -806,10 +806,10 @@ f13byte_t: TOK_f13 is TOK_B=1 & TOK_f13
{ export *[ram]:1 TOK_f13; }
f15_t: addr is TOK_f15
- [ addr = ( TOK_f15 << 1 ); ] { tmp:2 = addr; export *[ram]:2 tmp; }
+ [ addr = ( TOK_f15 << 1 ); ] { export *[ram]:2 addr; }
f15b_t: addr is TOK_f15b
- [ addr = ( TOK_f15b << 1 ); ] { tmp:2 = addr; export *[ram]:2 tmp; }
+ [ addr = ( TOK_f15b << 1 ); ] { export *[ram]:2 addr; }
k3_t: "#"TOK_k3 is TOK_k3
{ export *[const]:1 TOK_k3; }
@@ -3992,6 +3992,8 @@ define pcodeop pic30_rem2;
Wnd_t = -shift;
}
+# TODO: locate encoding details for FEX instruction
+# :fex
:ff1l Ws_t,Wnd_t is OP_23_20=0xC & OP_19_16=0xF & OP_15_12=0x8 & OP_11=0x0 & Wnd_t & $(WSconstraint) & Ws_t {
@@ -7609,6 +7611,12 @@ define pcodeop pwrsavOp;
testSRL_Z(Wnd_t);
}
+# SSTEP - ICD instruction compatible with Microchips ICD debugging hardware
+# TODO: locate encoding details for SSTEP instruction
+# define pcodeop sstep;
+# :sstep is OP_23_0=?? {
+# sstep(); # In-Circuit Debugger (ICD) Single Step
+# }
:sub.w f13_t^WREG_t is OP_23_20=0xB & OP_19_16=0x5 & OP_15=0 & WREG_t & f13_t {
@@ -8184,6 +8192,11 @@ define pcodeop verifyslave;
}
@endif
+# URUN - ICD instruction compatible with Microchips ICD debugging hardware
+define pcodeop urun;
+:urun is OP_23_0=0xDAC000 {
+ urun(); # In-Circuit Debugger (ICD) Run
+}
:xor.w f13_t^WREG_t is OP_23_20=0xB & OP_19_16=0x6 & OP_15=1 & WREG_t & f13_t {
diff --git a/Ghidra/Processors/PIC/data/languages/PIC30.dwarf b/Ghidra/Processors/PIC/data/languages/PIC30.dwarf
new file mode 100644
index 0000000000..4f79ae17af
--- /dev/null
+++ b/Ghidra/Processors/PIC/data/languages/PIC30.dwarf
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Ghidra/Processors/PIC/data/languages/PIC33.dwarf b/Ghidra/Processors/PIC/data/languages/PIC33.dwarf
new file mode 100644
index 0000000000..f3643f01e5
--- /dev/null
+++ b/Ghidra/Processors/PIC/data/languages/PIC33.dwarf
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Ghidra/Processors/PIC/src/main/java/ghidra/app/plugin/core/analysis/Pic24DInitAnalyzer.java b/Ghidra/Processors/PIC/src/main/java/ghidra/app/plugin/core/analysis/Pic24DInitAnalyzer.java
new file mode 100644
index 0000000000..95f5ac3ae7
--- /dev/null
+++ b/Ghidra/Processors/PIC/src/main/java/ghidra/app/plugin/core/analysis/Pic24DInitAnalyzer.java
@@ -0,0 +1,162 @@
+/* ###
+ * 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.plugin.core.analysis;
+
+import ghidra.app.services.*;
+import ghidra.app.util.importer.MessageLog;
+import ghidra.app.util.opinion.ElfLoader;
+import ghidra.program.model.address.*;
+import ghidra.program.model.data.*;
+import ghidra.program.model.listing.*;
+import ghidra.program.model.mem.*;
+import ghidra.program.model.scalar.Scalar;
+import ghidra.program.model.symbol.*;
+import ghidra.program.model.util.CodeUnitInsertionException;
+import ghidra.util.GhidraDataConverter;
+import ghidra.util.Msg;
+import ghidra.util.exception.AssertException;
+import ghidra.util.exception.CancelledException;
+import ghidra.util.task.TaskMonitor;
+
+public class Pic24DInitAnalyzer extends AbstractAnalyzer {
+
+ private static final int DST_ORDINAL = 0;
+ private static final int LEN_ORDINAL = 1;
+ private static final int FORMAT_ORDINAL = 2;
+ private static final int PAGE_ORDINAL = 3;
+
+ public Pic24DInitAnalyzer() {
+ super("DInit Analyzer", "Processes .dinit Data Initialization Section", AnalyzerType.BYTE_ANALYZER);
+ setPriority(AnalysisPriority.BLOCK_ANALYSIS.before());
+ setDefaultEnablement(true);
+ }
+
+ @Override
+ public boolean canAnalyze(Program program) {
+ String processorName = program.getLanguage().getProcessor().toString();
+ boolean isSupportedProcessor =
+ processorName.contentEquals("PIC-24") || processorName.startsWith("dsPIC3");
+ if (!isSupportedProcessor) {
+ return false;
+ }
+ if (!ElfLoader.ELF_NAME.equals(program.getExecutableFormat())) {
+ return false;
+ }
+ return program.getMemory().getBlock(".dinit") != null;
+ }
+
+ @Override
+ public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log)
+ throws CancelledException {
+
+ Listing listing = program.getListing();
+ ReferenceManager referenceManager = program.getReferenceManager();
+
+ MemoryBlock dinitBlock = program.getMemory().getBlock(".dinit");
+ if (listing.getDefinedDataContaining(dinitBlock.getStart()) != null) {
+ Msg.info(this, "Skipping .dinit processing due to existing data at " + dinitBlock.getStart());
+ return true;
+ }
+
+ MemoryBufferImpl memBuffer = new MemoryBufferImpl(program.getMemory(), dinitBlock.getStart());
+ long available = dinitBlock.getSize();
+
+ Structure dataRecordType = new StructureDataType("data_record", 0, program.getDataTypeManager());
+ dataRecordType.setInternallyAligned(true);
+ dataRecordType.add(PointerDataType.dataType, "dst", null);
+ // NOTE: long is used instead of int to ensure that 4-bytes within ROM are consumed
+ dataRecordType.add(LongDataType.dataType, "len", null);
+ try {
+ dataRecordType.addBitField(LongDataType.dataType, 7, "format", null); // Valid formats: 0, 1, 2
+ dataRecordType.addBitField(LongDataType.dataType, 9, "page", null); // TODO: factor into dst ram reference
+ } catch (InvalidDataTypeException e) {
+ throw new AssertException(e);
+ }
+ dataRecordType.setFlexibleArrayComponent(ByteDataType.dataType, "data", null);
+
+ dataRecordType = (Structure) program.getDataTypeManager().resolve(dataRecordType, null);
+
+ GhidraDataConverter converter = GhidraDataConverter.getInstance(false);
+
+ AddressSpace dataSpace = program.getLanguage().getDefaultDataSpace();
+
+ try {
+ Address addr = dinitBlock.getStart();
+ int offset = 0;
+ while (offset < available) {
+ short dst = converter.getShort(memBuffer, offset);
+ if (dst == 0) {
+ break;
+ }
+ Data dataRecord = listing.createData(addr, dataRecordType);
+
+ Scalar len = (Scalar) dataRecord.getComponent(LEN_ORDINAL).getValue();
+ Scalar format = (Scalar) dataRecord.getComponent(FORMAT_ORDINAL).getValue();
+ Scalar page = (Scalar) dataRecord.getComponent(PAGE_ORDINAL).getValue();
+
+ // replace dst reference
+ Reference ref = referenceManager.getPrimaryReferenceFrom(addr, 0);
+ if (ref != null) {
+ referenceManager.delete(ref); // remove bad ref into ROM space
+ }
+ // TODO: use page
+ Address dstAddr = dataSpace.getAddress(dst & 0x0ffff);
+ referenceManager.addMemoryReference(addr, dstAddr, RefType.DATA, SourceType.ANALYSIS, 0);
+
+ offset += dataRecordType.getLength();
+ addr = addr.add(dataRecord.getLength());
+
+ Data arrayData = null;
+ long fmt = format.getValue();
+ if (fmt != 0) {
+ int flexArrayLen = 0;
+ if (fmt == 1) { // 2-bytes consumed per 4-byte ROM location
+ flexArrayLen = (int)(4 * ((len.getValue() + 1) / 2));
+ }
+ else if (fmt == 2) { // 3-bytes consumed per 4-byte ROM location
+ flexArrayLen = (int)(4 * ((len.getValue() + 2) / 3));
+ }
+ else {
+ Msg.error(this, "Invalid .dinit format value at " + dataRecord.getComponent(FORMAT_ORDINAL).getAddress());
+ break;
+ }
+
+ // bounds check
+ if (flexArrayLen < 0 || (offset + flexArrayLen) > available) {
+ Msg.error(this, "Invalid .dinit len value at " + dataRecord.getComponent(LEN_ORDINAL).getAddress());
+ break;
+ }
+
+ Array flexArray = new ArrayDataType(ByteDataType.dataType, flexArrayLen, 1);
+ arrayData = listing.createData(addr, flexArray);
+
+ offset += flexArrayLen;
+ addr = addr.add(flexArrayLen);
+ }
+
+ // NOTE: ELF Loader already loads initialized data intended for ROM into mapped RAM regions
+ // TODO: determine if it is necessary to perform actual initialization
+ // initializeData(program, dstAddr, arrayData, fmt, len);
+
+ }
+ } catch (MemoryAccessException | CodeUnitInsertionException e) {
+ Msg.error(this, "Failed during .dinit processing: " + e.getMessage());
+ }
+
+ return true;
+ }
+
+}
diff --git a/Ghidra/Processors/PIC/src/main/java/ghidra/app/util/bin/format/elf/extend/PIC30_ElfExtension.java b/Ghidra/Processors/PIC/src/main/java/ghidra/app/util/bin/format/elf/extend/PIC30_ElfExtension.java
index e563eeb766..8442870220 100644
--- a/Ghidra/Processors/PIC/src/main/java/ghidra/app/util/bin/format/elf/extend/PIC30_ElfExtension.java
+++ b/Ghidra/Processors/PIC/src/main/java/ghidra/app/util/bin/format/elf/extend/PIC30_ElfExtension.java
@@ -29,7 +29,61 @@ public class PIC30_ElfExtension extends ElfExtension {
public static final int EM_DSPIC30F = 118; /* Microchip Technology dsPIC30F DSC */
+ // ELF Header Flags (e_flags)
+ public static final int P30F = 1 << 0;
+ public static final int P30FSMPS = 1 << 1;
+ public static final int P33F = 1 << 2;
+ public static final int P24F = 1 << 3;
+ public static final int P24H = 1 << 4;
+ public static final int P24FK = 1 << 5;
+ public static final int P33E = 1 << 6;
+ public static final int P24E = 1 << 7;
+
+ // Section Header Flags (sh_flags)
+ public static final int SHF_MEMORY = (1 << 18); /* User-defined memory */
+ public static final int SHF_UNUSED = (1 << 19); /* Unused */
+ /* OS and processor-specific flags start at postion 20 */
+ public static final int SHF_SECURE = (1 << 20); /* Secure segment */
+ public static final int SHF_BOOT = (1 << 21); /* Boot segment */
+ public static final int SHF_DMA = (1 << 22); /* DMA memory */
+ public static final int SHF_NOLOAD = (1 << 23); /* Do not allocate or load */
+ public static final int SHF_NEAR = (1 << 24); /* Near memory */
+ public static final int SHF_PERSIST = (1 << 25); /* Persistent */
+ public static final int SHF_XMEM = (1 << 26); /* X Memory */
+ public static final int SHF_YMEM = (1 << 27); /* Y Memory */
public static final int SHF_PSV = (1 << 28); /* Constants in program memory */
+ public static final int SHF_EEDATA = (1 << 29); /* Data Flash memory */
+ public static final int SHF_ABSOLUTE = (1 << 30); /* Absolute address */
+ public static final int SHF_REVERSE = (1 << 31); /* Reverse aligned */
+
+ /**
+ NOTES:
+
+ EDS/PSV Sections - section data resides with ROM space but is accessable via the
+ the RAM data space at 0x8000 - 0xFFFF with the use of page register. Page use
+ may vary by CPU (EDS, PSV low-word access, PSV high-word access). PSV high-word
+ access capability is only provided when EDS is supported. See page registers
+ DSRPAG and DSWPAG. Page registers must be non-zero when used. Page boundary
+ handling must be explicitly handled in code. EDS memory may be directly
+ accessed provided the page register as been
+
+ Three ways to access page memory:
+
+ 1. Direct access using DSRPAG/DSWPAGpage registers (PIC24E, dsPIC33E and dsPIC33C).
+ With read/write page register set to non-zero value, offset 0..0x7FFF within
+ the page may be directly accessed by first setting bit-15 of offset before
+ performing a load or store to the range 0x8000..0xFFFF.
+
+ 2. Table read/write instruction may be used by setting TBLPAG register and
+ performing operation with a table offset in the range 0..0x7FFF.
+
+ 3. PSV direct access with PSVPAG register (PIC24F, PIC24H, dsPIC30F AND dsPIC33F).
+ Set PSV bit of CORCONL register, set page in PSVPAG register (macro psvpage() used
+ to obtain page from symbol). Access location with offset 0..0x7FFF (macro psvoffset() used
+ to obtain offset from symbol). Macro produces offset in the range 0x8000..0xFFFF.
+
+
+ **/
@Override
public boolean canHandle(ElfHeader elf) {
@@ -84,11 +138,30 @@ public class PIC30_ElfExtension extends ElfExtension {
private boolean isDataLoad(ElfSectionHeader section) {
if (!section.isAlloc()) {
- return false;
+ return isDebugSection(section);
}
return !section.isExecutable();
}
-
+
+ private boolean isDataLoad(MemoryLoadable loadable) {
+ if (loadable instanceof ElfSectionHeader) {
+ return isDataLoad((ElfSectionHeader)loadable);
+ }
+ return isDataLoad((ElfProgramHeader)loadable);
+ }
+
+ private boolean isDebugSection(ElfSectionHeader section) {
+ String name = section.getNameAsString();
+ return name.startsWith(".debug_") || ".comment".equals(name);
+ }
+
+ private boolean isDebugSection(MemoryLoadable loadable) {
+ if (loadable instanceof ElfSectionHeader) {
+ return isDebugSection((ElfSectionHeader)loadable);
+ }
+ return false;
+ }
+
@Override
public long getAdjustedLoadSize(ElfProgramHeader elfProgramHeader) {
long fileSize = elfProgramHeader.getFileSize();
@@ -111,48 +184,60 @@ public class PIC30_ElfExtension extends ElfExtension {
public InputStream getFilteredLoadInputStream(ElfLoadHelper elfLoadHelper,
MemoryLoadable loadable, Address start, long dataLength, InputStream dataInput) {
Language language = elfLoadHelper.getProgram().getLanguage();
- if (!language.getDefaultDataSpace().equals(start.getAddressSpace().getPhysicalSpace())) {
+ if (!isDataLoad(loadable) && !language.getDefaultDataSpace().equals(start.getAddressSpace().getPhysicalSpace())) {
return dataInput;
}
if (loadable instanceof ElfSectionHeader) {
ElfSectionHeader section = (ElfSectionHeader) loadable;
- if ((section.getFlags() & SHF_PSV) != 0) {
+ if (!elfLoadHelper.getElfHeader().isRelocatable() && (section.getFlags() & SHF_PSV) != 0) {
// TODO: this is really mapped into ROM space where PT_LOAD was done to physical memory
// In the absence of suitable mapping, we will load into RAM space
return new PIC30FilteredPSVDataInputStream(dataInput);
}
}
+ else {
+ return new PIC30FilteredPSVDataInputStream(dataInput);
+ }
// Data space loading pads after every byte with Microchip toolchain
// NOTE: this could vary and we may need to improve detection of this situation
- return new PIC30FilteredDataInputStream(dataInput);
+ return new PIC30FilteredDataInputStream(dataInput, !isDebugSection(loadable));
}
@Override
public boolean hasFilteredLoadInputStream(ElfLoadHelper elfLoadHelper, MemoryLoadable loadable,
Address start) {
+ if (loadable == null) {
+ return false;
+ }
+ if (isDataLoad(loadable)) {
+ return true;
+ }
Language language = elfLoadHelper.getProgram().getLanguage();
return language.getDefaultDataSpace().equals(start.getAddressSpace().getPhysicalSpace());
}
-
+
private static class PIC30FilteredDataInputStream extends FilterInputStream {
// BYTES:
protected boolean padByteToggle;
protected long pos;
-
- protected PIC30FilteredDataInputStream(InputStream in) {
+
+ private final boolean checkPadding;
+
+ protected PIC30FilteredDataInputStream(InputStream in, boolean checkPadding) {
super(in);
padByteToggle = false; // first byte is data not padding
+ this.checkPadding = checkPadding;
}
protected int readNextByte() throws IOException {
int r = in.read();
- if (padByteToggle && r != 0) {
- // expected padding
+ if (checkPadding && padByteToggle && r != 0) {
+ // expected padding - debug sections appear to be inconsistent with filler
throw new IOException("expected Data padding byte, pos=" + pos);
}
++pos;
@@ -204,7 +289,7 @@ public class PIC30_ElfExtension extends ElfExtension {
private boolean firstByteToggle; // firstByte of data or pad
protected PIC30FilteredPSVDataInputStream(InputStream in) {
- super(in);
+ super(in, true);
firstByteToggle = true;
}
diff --git a/Ghidra/Processors/PIC/src/main/java/ghidra/app/util/bin/format/elf/relocation/PIC30_ElfRelocationContext.java b/Ghidra/Processors/PIC/src/main/java/ghidra/app/util/bin/format/elf/relocation/PIC30_ElfRelocationContext.java
new file mode 100644
index 0000000000..20e43df9a9
--- /dev/null
+++ b/Ghidra/Processors/PIC/src/main/java/ghidra/app/util/bin/format/elf/relocation/PIC30_ElfRelocationContext.java
@@ -0,0 +1,46 @@
+/* ###
+ * 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.elf.relocation;
+
+import java.util.Map;
+
+import ghidra.app.util.bin.format.elf.ElfLoadHelper;
+import ghidra.app.util.bin.format.elf.ElfRelocationTable;
+import ghidra.app.util.bin.format.elf.ElfSymbol;
+import ghidra.program.model.address.Address;
+import ghidra.program.model.address.AddressSpace;
+
+class PIC30_ElfRelocationContext extends ElfRelocationContext {
+
+ protected PIC30_ElfRelocationContext(ElfRelocationHandler handler, ElfLoadHelper loadHelper,
+ ElfRelocationTable relocationTable, Map symbolMap) {
+ super(handler, loadHelper, relocationTable, symbolMap);
+ }
+
+ private boolean isDebugSection(AddressSpace overlaySpace) {
+ String name = overlaySpace.getName();
+ return name.startsWith(".debug_") || ".comment".equals(name);
+ }
+
+ @Override
+ public Address getRelocationAddress(Address baseAddress, long relocOffset) {
+ if (!baseAddress.isLoadedMemoryAddress() && isDebugSection(baseAddress.getAddressSpace())) {
+ relocOffset = relocOffset >> 1;
+ }
+ return baseAddress.addWrap(relocOffset);
+ }
+
+}
diff --git a/Ghidra/Processors/PIC/src/main/java/ghidra/app/util/bin/format/elf/relocation/PIC30_ElfRelocationHandler.java b/Ghidra/Processors/PIC/src/main/java/ghidra/app/util/bin/format/elf/relocation/PIC30_ElfRelocationHandler.java
index 87ccb6a1c6..6059bd0968 100644
--- a/Ghidra/Processors/PIC/src/main/java/ghidra/app/util/bin/format/elf/relocation/PIC30_ElfRelocationHandler.java
+++ b/Ghidra/Processors/PIC/src/main/java/ghidra/app/util/bin/format/elf/relocation/PIC30_ElfRelocationHandler.java
@@ -15,8 +15,11 @@
*/
package ghidra.app.util.bin.format.elf.relocation;
+import java.util.Map;
+
import ghidra.app.util.bin.format.elf.*;
import ghidra.program.model.address.Address;
+import ghidra.program.model.lang.Register;
import ghidra.program.model.listing.Program;
import ghidra.program.model.mem.Memory;
import ghidra.program.model.mem.MemoryAccessException;
@@ -24,16 +27,78 @@ import ghidra.util.exception.NotFoundException;
public class PIC30_ElfRelocationHandler extends ElfRelocationHandler {
- /* ARC Relocations */
+ /* PIC30 Relocation Types */
- //Numbers found in ./include/elf/arc.h:
+ // Numbers found in ./include/elf/pic30.h:
public static final int R_PIC30_NONE = 0;
public static final int R_PIC30_8 = 1;
public static final int R_PIC30_16 = 2;
public static final int R_PIC30_32 = 3;
+ public static final int R_PIC30_FILE_REG_BYTE = 4;
+ public static final int R_PIC30_FILE_REG = 5;
+ public static final int R_PIC30_FILE_REG_WORD = 6;
public static final int R_PIC30_FILE_REG_WORD_WITH_DST = 7;
public static final int R_PIC30_WORD = 8;
+ public static final int R_PIC30_PBYTE = 9;
+ public static final int R_PIC30_PWORD = 10;
+ public static final int R_PIC30_HANDLE = 11;
+ public static final int R_PIC30_PADDR = 12;
+ public static final int R_PIC30_P_PADDR = 13;
+ public static final int R_PIC30_PSVOFFSET = 14;
+ public static final int R_PIC30_TBLOFFSET = 15;
+ public static final int R_PIC30_WORD_HANDLE = 16;
+ public static final int R_PIC30_WORD_PSVOFFSET = 17;
+ public static final int R_PIC30_PSVPAGE = 18;
+ public static final int R_PIC30_P_PSVPAGE = 19;
+ public static final int R_PIC30_WORD_PSVPAGE = 20;
+ public static final int R_PIC30_WORD_TBLOFFSET = 21;
+ public static final int R_PIC30_TBLPAGE = 22;
+ public static final int R_PIC30_P_TBLPAGE = 23;
+ public static final int R_PIC30_WORD_TBLPAGE = 24;
+ public static final int R_PIC30_P_HANDLE = 25;
+ public static final int R_PIC30_P_PSVOFFSET = 26;
+ public static final int R_PIC30_P_TBLOFFSET = 27;
public static final int R_PIC30_PCREL_BRANCH = 28;
+ public static final int R_PIC30_BRANCH_ABSOLUTE = 29;
+ public static final int R_PIC30_PCREL_DO = 30;
+ public static final int R_PIC30_DO_ABSOLUTE = 31;
+ public static final int R_PIC30_PGM_ADDR_LSB = 32;
+ public static final int R_PIC30_PGM_ADDR_MSB = 33;
+ public static final int R_PIC30_UNSIGNED_4 = 34;
+ public static final int R_PIC30_UNSIGNED_5 = 35;
+ public static final int R_PIC30_BIT_SELECT_3 = 36;
+ public static final int R_PIC30_BIT_SELECT_4_BYTE = 37;
+ public static final int R_PIC30_BIT_SELECT_4 = 38;
+ public static final int R_PIC30_DSP_6 = 39;
+ public static final int R_PIC30_DSP_PRESHIFT = 40;
+ public static final int R_PIC30_SIGNED_10_BYTE = 41;
+ public static final int R_PIC30_UNSIGNED_10 = 42;
+ public static final int R_PIC30_UNSIGNED_14 = 43;
+ public static final int R_PIC30_FRAME_SIZE = 44;
+ public static final int R_PIC30_PWRSAV_MODE = 45;
+ public static final int R_PIC30_DMAOFFSET = 46;
+ public static final int R_PIC30_P_DMAOFFSET = 47;
+ public static final int R_PIC30_WORD_DMAOFFSET = 48;
+ public static final int R_PIC30_PSVPTR = 49;
+ public static final int R_PIC30_P_PSVPTR = 50;
+ public static final int R_PIC30_L_PSVPTR = 51;
+ public static final int R_PIC30_WORD_PSVPTR = 52;
+ public static final int R_PIC30_CALL_ACCESS = 53;
+ public static final int R_PIC30_PCREL_ACCESS = 54;
+ public static final int R_PIC30_ACCESS = 55;
+ public static final int R_PIC30_P_ACCESS = 56;
+ public static final int R_PIC30_L_ACCESS = 57;
+ public static final int R_PIC30_WORD_ACCESS = 58;
+ public static final int R_PIC30_EDSPAGE = 59;
+ public static final int R_PIC30_P_EDSPAGE = 60;
+ public static final int R_PIC30_WORD_EDSPAGE = 61;
+ public static final int R_PIC30_EDSOFFSET = 62;
+ public static final int R_PIC30_P_EDSOFFSET = 63;
+ public static final int R_PIC30_WORD_EDSOFFSET = 64;
+ public static final int R_PIC30_UNSIGNED_8 = 65;
+
+ // cached state assumes new instance created for each import use
+ private Boolean isEDSVariant = null;
@Override
public boolean canRelocate(ElfHeader elf) {
@@ -41,8 +106,24 @@ public class PIC30_ElfRelocationHandler extends ElfRelocationHandler {
}
@Override
- public void relocate(ElfRelocationContext elfRelocationContext, ElfRelocation relocation,
- Address relocationAddress) throws MemoryAccessException, NotFoundException {
+ public PIC30_ElfRelocationContext createRelocationContext(ElfLoadHelper loadHelper,
+ ElfRelocationTable relocationTable, Map symbolMap) {
+ return new PIC30_ElfRelocationContext(this, loadHelper, relocationTable, symbolMap);
+ }
+
+ private boolean isEDSVariant(ElfRelocationContext elfRelocationContext) {
+ if (isEDSVariant == null) {
+ // NOTE: non-EDS variants may improperly define DSRPAG
+ // in register space which should be corrected
+ Register reg = elfRelocationContext.program.getRegister("DSRPAG");
+ isEDSVariant = reg != null && reg.getAddressSpace().isMemorySpace();
+ }
+ return isEDSVariant;
+ }
+
+ @Override
+ public void relocate(ElfRelocationContext elfRelocationContext, ElfRelocation relocation, Address relocationAddress)
+ throws MemoryAccessException, NotFoundException {
int type = relocation.getType();
if (type == R_PIC30_NONE) {
@@ -54,57 +135,71 @@ public class PIC30_ElfRelocationHandler extends ElfRelocationHandler {
int symbolIndex = relocation.getSymbolIndex();
- long addend = relocation.getAddend(); // will be 0 for REL case
+ int addend = (int) relocation.getAddend();
- if (symbolIndex == 0) {//TODO
+ if (symbolIndex == 0) {// TODO
return;
}
- long offset = (int) relocationAddress.getOffset();
+ long relocWordOffset = (int) relocationAddress.getAddressableWordOffset();
ElfSymbol sym = elfRelocationContext.getSymbol(symbolIndex);
- long symbolValue = elfRelocationContext.getSymbolValue(sym);
+ int symbolValue = (int) elfRelocationContext.getSymbolValue(sym); // word offset
int oldValue = memory.getInt(relocationAddress);
+ short oldShortValue = memory.getShort(relocationAddress);
+
int newValue;
ElfHeader elf = elfRelocationContext.getElfHeader();
- if (elf.e_machine() == ElfConstants.EM_DSPIC30F) {//Defined in ./bfd/elf32-arc.c:
+ if (elf.e_machine() == ElfConstants.EM_DSPIC30F) {
switch (type) {
- case R_PIC30_32:
- newValue = (((int) symbolValue + (int) addend + oldValue) & 0xffffffff);
- memory.setInt(relocationAddress, newValue);
- break;
- case R_PIC30_PCREL_BRANCH:
- int offsetValue = memory.getShort(relocationAddress) + 1;
- offsetValue = offsetValue * 2; // make it byte oriented - this should normally be 0
- newValue = (int) (((symbolValue + (int) addend - (offset + 4))));
- newValue >>>= 2; // turn it into word offset, and align to even address, actually an error if it isn't aligned
- // work it into the instruction
- memory.setShort(relocationAddress, (short) (newValue & 0xffff));
- break;
- case R_PIC30_16:
- short oldShortValue = memory.getShort(relocationAddress);
- newValue = ((((int) symbolValue + (int) addend + oldShortValue) >> 1) & 0xffff);
- memory.setShort(relocationAddress, (short) newValue);
- break;
- case R_PIC30_FILE_REG_WORD_WITH_DST:
- newValue = ((((int) symbolValue + (int) addend) >> 1) & 0x7fff);
- int dst = (oldValue >> 4) & 0x7fff;
- newValue = ((newValue + dst) << 4) | (oldValue & 0xfff1000f);
- memory.setInt(relocationAddress, newValue);
- break;
- case R_PIC30_WORD:
- newValue = ((((int) symbolValue + (int) addend) >> 1) & 0xffff);
- newValue = (newValue << 4) | oldValue;
- memory.setInt(relocationAddress, newValue);
- break;
- case R_PIC30_8:
- default:
- String symbolName = sym.getNameAsString();
- markAsUnhandled(program, relocationAddress, type, symbolIndex, symbolName,
+ case R_PIC30_16: // 2
+ newValue = (symbolValue + addend + oldShortValue) & 0xffff;
+ memory.setShort(relocationAddress, (short) newValue);
+ break;
+ case R_PIC30_32: // 3
+ newValue = symbolValue + addend + oldValue;
+ memory.setInt(relocationAddress, newValue);
+ break;
+ case R_PIC30_FILE_REG_WORD_WITH_DST: // 7
+ int reloc = symbolValue >> 1;
+ reloc += addend;
+ reloc += oldValue >> 4;
+ reloc &= 0x7fff;
+ newValue = (reloc << 4) | (oldValue & ~0x7fff0);
+ memory.setInt(relocationAddress, newValue);
+ break;
+ case R_PIC30_WORD: // 8
+ case R_PIC30_WORD_TBLOFFSET: // 0x15
+ reloc = symbolValue;
+ reloc += addend;
+ reloc += oldValue >> 4;
+ reloc &= 0xffff;
+ newValue = (reloc << 4) | (oldValue & ~0x0ffff0);
+ memory.setInt(relocationAddress, newValue);
+ break;
+ case R_PIC30_WORD_TBLPAGE: // 0x18
+ reloc = symbolValue >> 16;
+ reloc += addend;
+ reloc += oldValue >> 4;
+ reloc &= 0xffff;
+ if (isEDSVariant(elfRelocationContext)) {
+ reloc |= 0x100;
+ }
+ newValue = (reloc << 4) | (oldValue & ~0x0ffff0);
+ memory.setInt(relocationAddress, newValue);
+ break;
+ case R_PIC30_PCREL_BRANCH: // 0x1c
+ newValue = (int) (symbolValue - relocWordOffset + oldShortValue - 2);
+ newValue >>>= 1;
+ memory.setShort(relocationAddress, (short) (newValue & 0xffff));
+ break;
+ default:
+ String symbolName = sym.getNameAsString();
+ markAsUnhandled(program, relocationAddress, type, symbolIndex, symbolName,
elfRelocationContext.getLog());
- break;
+ break;
}
}
}
diff --git a/Ghidra/RuntimeScripts/Common/support/analyzeHeadlessREADME.html b/Ghidra/RuntimeScripts/Common/support/analyzeHeadlessREADME.html
index e8590b31e8..00b7bd9cb9 100644
--- a/Ghidra/RuntimeScripts/Common/support/analyzeHeadlessREADME.html
+++ b/Ghidra/RuntimeScripts/Common/support/analyzeHeadlessREADME.html
@@ -589,6 +589,7 @@ The Headless Analyzer uses the command-line parameters discussed below. See -loader-loadExternalLibs <true|false>
-loader-applyRelocations <true|false>
-loader-imagebase <imagebase3 >
+ -loader-dataImageBase <dataImageBase4 >
-loader-includeOtherBlocks <true|false>
-loader-resolveExternalSymbols <true|false>
@@ -609,9 +610,11 @@ The Headless Analyzer uses the command-line parameters discussed below. See
- 1. Address must be in the form [space:]offset. Space is optional, and offset is a hex value with no leading 0x.
- 2. To specify hexadecimal, use a leading 0x.
- 3. Address is in the default space, and must be specified as a hexadecimal value without the leading 0x.
+ 1 Address must be in the form [space:]offset. Space is optional, and offset is a hex value with no leading 0x.
+ 2 To specify hexadecimal, use a leading 0x.
+ 3 Base address is in the default space and must be specified as a hexadecimal value without the leading 0x.
+ 4 Base address is in the default data space and must be specified as a hexadecimal value without the leading 0x.
+ This option only applies to Harvard Architecture processors when loading relocatable ELF binaries (i.e., object modules).