Merge branch 'ghidra1_PIC30_ElfImportFixes'

This commit is contained in:
ghidra1 2020-05-14 15:33:29 -04:00
commit 305a1ddf98
28 changed files with 904 additions and 317 deletions

View file

@ -60,7 +60,7 @@
by importers. At this point in time there is no capability provided by the Memory Map provider to create a by importers. At this point in time there is no capability provided by the Memory Map provider to create a
new File Bytes instance.</P> new File Bytes instance.</P>
<P><B>Overlay</B> - Each of the above memory block types may optionally be specified as an <I>Overlay</I> at the <P><A name="OverlayType"></A><B>Overlay</B> - Each of the above memory block types may optionally be specified as an <I>Overlay</I> at the
time of creation. If this option is selected, the block is created in a new time of creation. If this option is selected, the block is created in a new
overlay address space.&nbsp; Overlay blocks can serve various overlay address space.&nbsp; Overlay blocks can serve various
purposes where a memory range may contain different data/code or map to different areas of memory purposes where a memory range may contain different data/code or map to different areas of memory

View file

@ -27,6 +27,7 @@ import ghidra.app.util.importer.MessageLog;
import ghidra.framework.options.Options; import ghidra.framework.options.Options;
import ghidra.program.model.address.AddressSetView; import ghidra.program.model.address.AddressSetView;
import ghidra.program.model.data.BuiltInDataTypeManager; import ghidra.program.model.data.BuiltInDataTypeManager;
import ghidra.program.model.lang.Language;
import ghidra.program.model.listing.Program; import ghidra.program.model.listing.Program;
import ghidra.util.Msg; import ghidra.util.Msg;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
@ -91,6 +92,15 @@ public class DWARFAnalyzer extends AbstractAnalyzer {
setSupportsOneTimeAnalysis(); 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 @Override
public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log) public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log)
throws CancelledException { throws CancelledException {

View file

@ -443,7 +443,7 @@ public class EntryPointAnalyzer extends AbstractAnalyzer {
} }
private boolean isLanguageDefinedEntry(Program program, Address addr) { private boolean isLanguageDefinedEntry(Program program, Address addr) {
List<AddressLabelInfo> labelList = program.getLanguage().getDefaultLabels(); List<AddressLabelInfo> labelList = program.getLanguage().getDefaultSymbols();
for (AddressLabelInfo info : labelList) { for (AddressLabelInfo info : labelList) {
if (addr.equals(info.getAddress())) { if (addr.equals(info.getAddress())) {
return info.isEntry(); return info.isEntry();
@ -453,7 +453,7 @@ public class EntryPointAnalyzer extends AbstractAnalyzer {
} }
private boolean isLanguageDefinedEntryPointer(Program program, Address addr) { private boolean isLanguageDefinedEntryPointer(Program program, Address addr) {
List<AddressLabelInfo> labelList = program.getLanguage().getDefaultLabels(); List<AddressLabelInfo> labelList = program.getLanguage().getDefaultSymbols();
for (AddressLabelInfo info : labelList) { for (AddressLabelInfo info : labelList) {
if (addr.equals(info.getAddress())) { if (addr.equals(info.getAddress())) {
ProcessorSymbolType type = info.getProcessorSymbolType(); ProcessorSymbolType type = info.getProcessorSymbolType();

View file

@ -110,6 +110,9 @@ public class ParamInfo {
} }
void setOrdinal(int i) { void setOrdinal(int i) {
if (original != null && original.getOrdinal() != i) {
original = null;
}
this.ordinal = i; this.ordinal = i;
} }

View file

@ -865,7 +865,7 @@ public class DIEAggregate {
// if the DWARF attr was a DW_FORM_addr, it doesn't need fixing up // if the DWARF attr was a DW_FORM_addr, it doesn't need fixing up
if (high.form == DWARFForm.DW_FORM_addr) { 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 // else it was a DW_FORM_data value and is relative to the lowPC value

View file

@ -605,7 +605,7 @@ public class DWARFFunctionImporter {
private final Address toAddr(Number offset) { private final Address toAddr(Number offset) {
return currentProgram.getAddressFactory().getDefaultAddressSpace().getAddress( return currentProgram.getAddressFactory().getDefaultAddressSpace().getAddress(
offset.longValue()); offset.longValue(), true);
} }
/** /**

View file

@ -630,12 +630,11 @@ public class ElfHeader implements StructConverter, Writeable {
} }
ArrayList<ElfStringTable> stringTableList = new ArrayList<>(); ArrayList<ElfStringTable> stringTableList = new ArrayList<>();
for (int i = 0; i < sectionHeaders.length; ++i) { for (ElfSectionHeader stringTableSectionHeader : sectionHeaders) {
if (sectionHeaders[i].getType() == ElfSectionHeaderConstants.SHT_STRTAB) { if (stringTableSectionHeader.getType() == ElfSectionHeaderConstants.SHT_STRTAB) {
ElfSectionHeader stringTableSectionHeader = sectionHeaders[i];
ElfStringTable stringTable = ElfStringTable.createElfStringTable(reader, this, ElfStringTable stringTable = ElfStringTable.createElfStringTable(reader, this,
stringTableSectionHeader, stringTableSectionHeader.getOffset(), stringTableSectionHeader, stringTableSectionHeader.getOffset(),
sectionHeaders[i].getAddress(), stringTableSectionHeader.getSize()); stringTableSectionHeader.getAddress(), stringTableSectionHeader.getSize());
stringTableList.add(stringTable); stringTableList.add(stringTable);
if (stringTable.getAddressOffset() == dynamicStringTableAddr) { if (stringTable.getAddressOffset() == dynamicStringTableAddr) {
dynamicStringTable = stringTable; dynamicStringTable = stringTable;
@ -703,10 +702,9 @@ public class ElfHeader implements StructConverter, Writeable {
// Add section based symbol tables // Add section based symbol tables
ArrayList<ElfSymbolTable> symbolTableList = new ArrayList<>(); ArrayList<ElfSymbolTable> symbolTableList = new ArrayList<>();
for (int i = 0; i < sectionHeaders.length; ++i) { for (ElfSectionHeader symbolTableSectionHeader : sectionHeaders) {
if (sectionHeaders[i].getType() == ElfSectionHeaderConstants.SHT_SYMTAB || if (symbolTableSectionHeader.getType() == ElfSectionHeaderConstants.SHT_SYMTAB ||
sectionHeaders[i].getType() == ElfSectionHeaderConstants.SHT_DYNSYM) { symbolTableSectionHeader.getType() == ElfSectionHeaderConstants.SHT_DYNSYM) {
ElfSectionHeader symbolTableSectionHeader = sectionHeaders[i];
if (symbolTableSectionHeader.getOffset() < 0) { if (symbolTableSectionHeader.getOffset() < 0) {
continue; 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 // HACK: 07/01/2013 - Added hack for malformed ELF file with only program header sections
ElfProgramHeader[] pheaders = getProgramHeaders(); ElfProgramHeader[] pheaders = getProgramHeaders();
long size = 0; long size = 0;
for (int i = 0; i < pheaders.length; i++) { for (ElfProgramHeader pheader : pheaders) {
size += pheaders[i].getFileSize(); size += pheader.getFileSize();
} }
if (size == fileLength) { if (size == fileLength) {
// adjust program section file offset to be based on relative read offset // adjust program section file offset to be based on relative read offset
long relOffset = 0; long relOffset = 0;
for (int i = 0; i < pheaders.length; i++) { for (ElfProgramHeader pheader : pheaders) {
pheaders[i].setOffset(relOffset); pheader.setOffset(relOffset);
relOffset += pheaders[i].getFileSize(); relOffset += pheader.getFileSize();
} }
} }
} }
@ -1322,9 +1320,9 @@ public class ElfHeader implements StructConverter, Writeable {
*/ */
public ElfSectionHeader[] getSections(int type) { public ElfSectionHeader[] getSections(int type) {
ArrayList<ElfSectionHeader> list = new ArrayList<>(); ArrayList<ElfSectionHeader> list = new ArrayList<>();
for (int i = 0; i < sectionHeaders.length; i++) { for (ElfSectionHeader sectionHeader : sectionHeaders) {
if (sectionHeaders[i].getType() == type) { if (sectionHeader.getType() == type) {
list.add(sectionHeaders[i]); list.add(sectionHeader);
} }
} }
ElfSectionHeader[] sections = new ElfSectionHeader[list.size()]; ElfSectionHeader[] sections = new ElfSectionHeader[list.size()];
@ -1340,15 +1338,17 @@ public class ElfHeader implements StructConverter, Writeable {
*/ */
public ElfSectionHeader getSection(String name) { public ElfSectionHeader getSection(String name) {
List<ElfSectionHeader> list = new ArrayList<>(); List<ElfSectionHeader> list = new ArrayList<>();
for (int i = 0; i < sectionHeaders.length; i++) { for (ElfSectionHeader sectionHeader : sectionHeaders) {
if (name != null && name.equals(sectionHeaders[i].getNameAsString())) { if (name != null && name.equals(sectionHeader.getNameAsString())) {
list.add(sectionHeaders[i]); list.add(sectionHeader);
} }
} }
if (list.size() == 0) if (list.size() == 0) {
return null; return null;
if (list.size() > 1) }
if (list.size() > 1) {
throw new RuntimeException(">1 section with name of " + name); throw new RuntimeException(">1 section with name of " + name);
}
return list.get(0); return list.get(0);
} }
@ -1359,9 +1359,9 @@ public class ElfHeader implements StructConverter, Writeable {
* @return the section header with the specified address * @return the section header with the specified address
*/ */
public ElfSectionHeader getSectionAt(long address) { public ElfSectionHeader getSectionAt(long address) {
for (int i = 0; i < sectionHeaders.length; i++) { for (ElfSectionHeader sectionHeader : sectionHeaders) {
if (sectionHeaders[i].getAddress() == address) { if (sectionHeader.getAddress() == address) {
return sectionHeaders[i]; return sectionHeader;
} }
} }
return null; return null;
@ -1375,14 +1375,14 @@ public class ElfHeader implements StructConverter, Writeable {
*/ */
public ElfSectionHeader getSectionLoadHeaderContaining(long address) { public ElfSectionHeader getSectionLoadHeaderContaining(long address) {
// FIXME: verify // FIXME: verify
for (int i = 0; i < sectionHeaders.length; i++) { for (ElfSectionHeader sectionHeader : sectionHeaders) {
if (!sectionHeaders[i].isAlloc()) { if (!sectionHeader.isAlloc()) {
continue; continue;
} }
long start = sectionHeaders[i].getAddress(); long start = sectionHeader.getAddress();
long end = start + sectionHeaders[i].getSize(); long end = start + sectionHeader.getSize();
if (start <= address && address <= end) { if (start <= address && address <= end) {
return sectionHeaders[i]; return sectionHeader;
} }
} }
return null; return null;
@ -1447,9 +1447,9 @@ public class ElfHeader implements StructConverter, Writeable {
*/ */
public ElfProgramHeader[] getProgramHeaders(int type) { public ElfProgramHeader[] getProgramHeaders(int type) {
ArrayList<ElfProgramHeader> list = new ArrayList<>(); ArrayList<ElfProgramHeader> list = new ArrayList<>();
for (int i = 0; i < programHeaders.length; i++) { for (ElfProgramHeader programHeader : programHeaders) {
if (programHeaders[i].getType() == type) { if (programHeader.getType() == type) {
list.add(programHeaders[i]); list.add(programHeader);
} }
} }
ElfProgramHeader[] arr = new ElfProgramHeader[list.size()]; ElfProgramHeader[] arr = new ElfProgramHeader[list.size()];
@ -1487,9 +1487,9 @@ public class ElfHeader implements StructConverter, Writeable {
* @return the program header with the specified address * @return the program header with the specified address
*/ */
public ElfProgramHeader getProgramHeaderAt(long virtualAddr) { public ElfProgramHeader getProgramHeaderAt(long virtualAddr) {
for (int i = 0; i < programHeaders.length; i++) { for (ElfProgramHeader programHeader : programHeaders) {
if (programHeaders[i].getVirtualAddress() == virtualAddr) { if (programHeader.getVirtualAddress() == virtualAddr) {
return programHeaders[i]; return programHeader;
} }
} }
return null; return null;
@ -1502,15 +1502,15 @@ public class ElfHeader implements StructConverter, Writeable {
* @return the program header with the specified address * @return the program header with the specified address
*/ */
public ElfProgramHeader getProgramLoadHeaderContaining(long virtualAddr) { public ElfProgramHeader getProgramLoadHeaderContaining(long virtualAddr) {
for (int i = 0; i < programHeaders.length; i++) { for (ElfProgramHeader programHeader : programHeaders) {
if (programHeaders[i] == null || if (programHeader == null ||
programHeaders[i].getType() != ElfProgramHeaderConstants.PT_LOAD) { programHeader.getType() != ElfProgramHeaderConstants.PT_LOAD) {
continue; continue;
} }
long start = programHeaders[i].getVirtualAddress(); long start = programHeader.getVirtualAddress();
long end = programHeaders[i].getAdjustedMemorySize() - 1 + start; long end = programHeader.getAdjustedMemorySize() - 1 + start;
if (virtualAddr >= start && virtualAddr <= end) { if (virtualAddr >= start && virtualAddr <= end) {
return programHeaders[i]; return programHeader;
} }
} }
return null; return null;
@ -1523,15 +1523,15 @@ public class ElfHeader implements StructConverter, Writeable {
* @return the program header with the specified file offset * @return the program header with the specified file offset
*/ */
public ElfProgramHeader getProgramLoadHeaderContainingFileOffset(long offset) { public ElfProgramHeader getProgramLoadHeaderContainingFileOffset(long offset) {
for (int i = 0; i < programHeaders.length; i++) { for (ElfProgramHeader programHeader : programHeaders) {
if (programHeaders[i] == null || if (programHeader == null ||
programHeaders[i].getType() != ElfProgramHeaderConstants.PT_LOAD) { programHeader.getType() != ElfProgramHeaderConstants.PT_LOAD) {
continue; continue;
} }
long start = programHeaders[i].getOffset(); long start = programHeader.getOffset();
long end = start + (programHeaders[i].getFileSize() - 1); long end = start + (programHeader.getFileSize() - 1);
if (offset >= start && offset <= end) { if (offset >= start && offset <= end) {
return programHeaders[i]; return programHeader;
} }
} }
return null; return null;
@ -1567,9 +1567,9 @@ public class ElfHeader implements StructConverter, Writeable {
* @return the string table associated to the specified section header * @return the string table associated to the specified section header
*/ */
public ElfStringTable getStringTable(ElfSectionHeader section) { public ElfStringTable getStringTable(ElfSectionHeader section) {
for (int i = 0; i < stringTables.length; i++) { for (ElfStringTable stringTable : stringTables) {
if (stringTables[i].getFileOffset() == section.getOffset()) { if (stringTable.getFileOffset() == section.getOffset()) {
return stringTables[i]; return stringTable;
} }
} }
return null; return null;
@ -1600,9 +1600,9 @@ public class ElfHeader implements StructConverter, Writeable {
if (symbolTableSection == null) { if (symbolTableSection == null) {
return null; return null;
} }
for (int i = 0; i < symbolTables.length; i++) { for (ElfSymbolTable symbolTable : symbolTables) {
if (symbolTables[i].getFileOffset() == symbolTableSection.getOffset()) { if (symbolTable.getFileOffset() == symbolTableSection.getOffset()) {
return symbolTables[i]; return symbolTable;
} }
} }
return null; return null;
@ -1633,9 +1633,9 @@ public class ElfHeader implements StructConverter, Writeable {
* @return the relocation table located at the specified fileOffset or null * @return the relocation table located at the specified fileOffset or null
*/ */
public ElfRelocationTable getRelocationTableAtOffset(long fileOffset) { public ElfRelocationTable getRelocationTableAtOffset(long fileOffset) {
for (int i = 0; i < relocationTables.length; i++) { for (ElfRelocationTable relocationTable : relocationTables) {
if (relocationTables[i].getFileOffset() == fileOffset) { if (relocationTable.getFileOffset() == fileOffset) {
return relocationTables[i]; return relocationTable;
} }
} }
return null; return null;
@ -1707,7 +1707,7 @@ public class ElfHeader implements StructConverter, Writeable {
* @return e_entry component ordinal * @return e_entry component ordinal
*/ */
public int getEntryComponentOrdinal() { public int getEntryComponentOrdinal() {
return 9; return 11;
} }
/** /**
@ -1716,7 +1716,7 @@ public class ElfHeader implements StructConverter, Writeable {
* @return e_phoff component ordinal * @return e_phoff component ordinal
*/ */
public int getPhoffComponentOrdinal() { public int getPhoffComponentOrdinal() {
return 10; return 12;
} }
/** /**
@ -1725,7 +1725,7 @@ public class ElfHeader implements StructConverter, Writeable {
* @return e_shoff component ordinal * @return e_shoff component ordinal
*/ */
public int getShoffComponentOrdinal() { public int getShoffComponentOrdinal() {
return 11; return 13;
} }
private void addSection(ElfSectionHeader newSection) { private void addSection(ElfSectionHeader newSection) {

View file

@ -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);
}
} }

View file

@ -179,7 +179,8 @@ public abstract class AbstractProgramLoader implements Loader {
public List<Option> getDefaultOptions(ByteProvider provider, LoadSpec loadSpec, public List<Option> getDefaultOptions(ByteProvider provider, LoadSpec loadSpec,
DomainObject domainObject, boolean isLoadIntoProgram) { DomainObject domainObject, boolean isLoadIntoProgram) {
ArrayList<Option> list = new ArrayList<>(); ArrayList<Option> 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")); Boolean.class, Loader.COMMAND_LINE_ARG_PREFIX + "-applyLabels"));
list.add(new Option(ANCHOR_LABELS_OPTION_NAME, true, Boolean.class, list.add(new Option(ANCHOR_LABELS_OPTION_NAME, true, Boolean.class,
Loader.COMMAND_LINE_ARG_PREFIX + "-anchorLabels")); Loader.COMMAND_LINE_ARG_PREFIX + "-anchorLabels"));
@ -404,50 +405,23 @@ public abstract class AbstractProgramLoader implements Loader {
private void applyProcessorLabels(List<Option> options, Program program) { private void applyProcessorLabels(List<Option> options, Program program) {
int id = program.startTransaction("Finalize load"); int id = program.startTransaction("Finalize load");
try { 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)) { if (shouldApplyProcessorLabels(options)) {
boolean anchorSymbols = shouldAnchorSymbols(options); boolean anchorSymbols = shouldAnchorSymbols(options);
Language lang = program.getLanguage(); List<AddressLabelInfo> labels = lang.getDefaultSymbols();
SymbolTable symTable = program.getSymbolTable();
List<AddressLabelInfo> labels = lang.getDefaultLabels();
for (AddressLabelInfo info : labels) { for (AddressLabelInfo info : labels) {
Address addr = info.getAddress(); createSymbol(program, info, anchorSymbols);
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
}
} }
} }
GhidraProgramUtilities.removeAnalyzedFlag(program); 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 { private String computeBinaryMD5(ByteProvider provider) throws IOException {
try (InputStream in = provider.getInputStream(0)) { try (InputStream in = provider.getInputStream(0)) {
return MD5Utilities.getMD5Hash(in); return MD5Utilities.getMD5Hash(in);

View file

@ -23,9 +23,8 @@ import ghidra.app.util.OptionUtils;
import ghidra.app.util.bin.ByteProvider; import ghidra.app.util.bin.ByteProvider;
import ghidra.app.util.bin.format.elf.ElfException; import ghidra.app.util.bin.format.elf.ElfException;
import ghidra.app.util.bin.format.elf.ElfHeader; import ghidra.app.util.bin.format.elf.ElfHeader;
import ghidra.program.model.address.AddressOutOfBoundsException; import ghidra.program.model.address.*;
import ghidra.program.model.address.AddressSpace; import ghidra.program.model.lang.*;
import ghidra.program.model.lang.LanguageNotFoundException;
import ghidra.util.NumericUtilities; import ghidra.util.NumericUtilities;
import ghidra.util.StringUtilities; import ghidra.util.StringUtilities;
@ -41,6 +40,8 @@ public class ElfLoaderOptionsFactory {
public static final String IMAGE_BASE_OPTION_NAME = "Image Base"; public static final String IMAGE_BASE_OPTION_NAME = "Image Base";
public static final long IMAGE_BASE_DEFAULT = 0x00010000; public static final long IMAGE_BASE_DEFAULT = 0x00010000;
public static final long IMAGE64_BASE_DEFAULT = 0x00100000L; 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 public static final String INCLUDE_OTHER_BLOCKS = "Import Non-Loaded Data";// as OTHER overlay blocks
static final boolean INCLUDE_OTHER_BLOCKS_DEFAULT = true; static final boolean INCLUDE_OTHER_BLOCKS_DEFAULT = true;
@ -66,12 +67,20 @@ public class ElfLoaderOptionsFactory {
if (imageBase == 0 && (elf.isRelocatable() || elf.isSharedObject())) { if (imageBase == 0 && (elf.isRelocatable() || elf.isSharedObject())) {
imageBase = elf.is64Bit() ? IMAGE64_BASE_DEFAULT : IMAGE_BASE_DEFAULT; imageBase = elf.is64Bit() ? IMAGE64_BASE_DEFAULT : IMAGE_BASE_DEFAULT;
} }
AddressSpace defaultSpace = Language language = loadSpec.getLanguageCompilerSpec().getLanguage();
loadSpec.getLanguageCompilerSpec().getLanguage().getDefaultSpace(); AddressSpace defaultSpace = language.getDefaultSpace();
String baseOffsetStr = getBaseOffsetString(imageBase, defaultSpace); String hexValueStr = getBaseAddressOffsetString(imageBase, defaultSpace);
options.add(new Option(IMAGE_BASE_OPTION_NAME, baseOffsetStr, String.class, options.add(new Option(IMAGE_BASE_OPTION_NAME, hexValueStr, String.class,
Loader.COMMAND_LINE_ARG_PREFIX + "-imagebase")); 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, options.add(new Option(INCLUDE_OTHER_BLOCKS, INCLUDE_OTHER_BLOCKS_DEFAULT, Boolean.class,
Loader.COMMAND_LINE_ARG_PREFIX + "-includeOtherBlocks")); Loader.COMMAND_LINE_ARG_PREFIX + "-includeOtherBlocks"));
@ -80,14 +89,56 @@ public class ElfLoaderOptionsFactory {
new Option(RESOLVE_EXTERNAL_SYMBOLS_OPTION_NAME, RESOLVE_EXTERNAL_SYMBOLS_DEFAULT, new Option(RESOLVE_EXTERNAL_SYMBOLS_OPTION_NAME, RESOLVE_EXTERNAL_SYMBOLS_DEFAULT,
Boolean.class, Loader.COMMAND_LINE_ARG_PREFIX + "-resolveExternalSymbols")); 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) { private static String getBaseAddressOffsetString(long imageBase, AddressSpace space) {
long maxOffset = defaultSpace.getMaxAddress().getAddressableWordOffset(); long maxOffset = space.getMaxAddress().getAddressableWordOffset();
while (Long.compareUnsigned(imageBase, maxOffset) > 0) { while (Long.compareUnsigned(imageBase, maxOffset) > 0) {
imageBase >>>= 4; imageBase >>>= 4;
} }
String baseOffsetStr = Long.toHexString(imageBase); 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(); int baseOffsetStrLen = baseOffsetStr.length();
if (baseOffsetStrLen < minNibbles) { if (baseOffsetStrLen < minNibbles) {
baseOffsetStr = baseOffsetStr =
@ -97,6 +148,12 @@ public class ElfLoaderOptionsFactory {
} }
static String validateOptions(LoadSpec loadSpec, List<Option> options) { static String validateOptions(LoadSpec loadSpec, List<Option> options) {
Language language;
try {
language = loadSpec.getLanguageCompilerSpec().getLanguage();
} catch (LanguageNotFoundException e) {
throw new RuntimeException(e);
}
for (Option option : options) { for (Option option : options) {
String name = option.getName(); String name = option.getName();
if (name.equals(PERFORM_RELOCATIONS_NAME)) { if (name.equals(PERFORM_RELOCATIONS_NAME)) {
@ -110,25 +167,29 @@ public class ElfLoaderOptionsFactory {
} }
} }
else if (name.equals(IMAGE_BASE_OPTION_NAME)) { else if (name.equals(IMAGE_BASE_OPTION_NAME)) {
if (!String.class.isAssignableFrom(option.getValueClass())) { return validateAddressSpaceOffsetOption(option, language.getDefaultSpace());
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);
}
} }
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; return null;
} }
@ -149,4 +210,9 @@ public class ElfLoaderOptionsFactory {
public static String getImageBaseOption(List<Option> options) { public static String getImageBaseOption(List<Option> options) {
return OptionUtils.getOption(IMAGE_BASE_OPTION_NAME, options, (String) null); 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

@ -19,8 +19,7 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.math.BigInteger; import java.math.BigInteger;
import java.text.NumberFormat; import java.text.NumberFormat;
import java.util.HashMap; import java.util.*;
import java.util.List;
import java.util.function.Consumer; import java.util.function.Consumer;
import ghidra.app.cmd.label.SetLabelPrimaryCmd; 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 static final int DISCARDABLE_SEGMENT_SIZE = 0xff;
private List<Option> options; private List<Option> options;
private Long dataImageBase; // cached data image base option or null if not applicable
private MessageLog log; private MessageLog log;
private ElfHeader elf; private ElfHeader elf;
@ -249,6 +249,17 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
Msg.error(this, "Can't set image base.", e); 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 { private void addProgramProperties(TaskMonitor monitor) throws CancelledException {
@ -709,7 +720,7 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
} }
private void processRelocationTable(ElfRelocationTable relocationTable, private void processRelocationTable(ElfRelocationTable relocationTable,
ElfRelocationContext context, AddressSpace relocationSpace, long baseOffset, ElfRelocationContext context, AddressSpace relocationSpace, long baseWordOffset,
TaskMonitor monitor) throws CancelledException { TaskMonitor monitor) throws CancelledException {
ElfSymbol[] symbols = relocationTable.getAssociatedSymbolTable().getSymbols(); ElfSymbol[] symbols = relocationTable.getAssociatedSymbolTable().getSymbols();
@ -725,8 +736,11 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
symbolName = symbols[symbolIndex].getNameAsString(); symbolName = symbols[symbolIndex].getNameAsString();
} }
long relocationOffset = baseOffset + reloc.getOffset(); Address baseAddress = relocationSpace.getTruncatedAddress(baseWordOffset, true);
Address relocAddr = relocationSpace.getTruncatedAddress(relocationOffset, 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() }; long[] values = new long[] { reloc.getSymbolIndex() };
@ -1261,6 +1275,7 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
short sectionIndex = elfSymbol.getSectionHeaderIndex(); short sectionIndex = elfSymbol.getSectionHeaderIndex();
Address symSectionBase = null; Address symSectionBase = null;
AddressSpace defaultSpace = getDefaultAddressSpace(); AddressSpace defaultSpace = getDefaultAddressSpace();
AddressSpace defaultDataSpace = getDefaultDataSpace();
AddressSpace symbolSpace = defaultSpace; AddressSpace symbolSpace = defaultSpace;
long symOffset = elfSymbol.getValue(); long symOffset = elfSymbol.getValue();
@ -1276,11 +1291,14 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
return null; return null;
} }
symbolSpace = symSectionBase.getAddressSpace(); symbolSpace = symSectionBase.getAddressSpace();
} // else assume sections have been stripped - always use default space } // else assume sections have been stripped
if (symbolSpace.getPhysicalSpace() == defaultSpace) { if (symbolSpace.getPhysicalSpace() == defaultSpace) {
symOffset = symOffset =
elf.adjustAddressForPrelink(symOffset) + getImageBaseWordAdjustmentOffset(); 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) else if (sectionIndex == ElfSectionHeaderConstants.SHN_UNDEF) { // Not section relative 0x0000 (e.g., no sections defined)
// FIXME: No sections defined or refers to external symbol // 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 // EXTERNAL block is affected by the program image base
symOffset += getImageBaseWordAdjustmentOffset(); 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 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) // The should potentially be assign a constant address instead (not possible currently)
// Note: Assume data space - symbols will be "pinned" // 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 { 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..."); monitor.setMessage("Processing program headers...");
boolean includeOtherBlocks = ElfLoaderOptionsFactory.includeOtherBlocks(options); 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(); ElfProgramHeader[] elfProgramHeaders = elf.getProgramHeaders();
for (int i = 0; i < elfProgramHeaders.length; ++i) { for (int i = 0; i < elfProgramHeaders.length; ++i) {
monitor.checkCanceled(); monitor.checkCanceled();
@ -2514,16 +2524,22 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
"] with invalid file offset"); "] with invalid file offset");
continue; 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 // 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 // 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 // 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) { if (fullSizeBytes <= 0) {
log("Skipping zero-length segment [" + segmentNumber + "," + log("Skipping zero-length segment [" + segmentNumber + "," +
elfProgramHeader.getDescription() + "] at address " + address.toString(true)); 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)) { if (!space.isValidRange(address.getOffset(), fullSizeBytes)) {
log("Skipping unloadable segment [" + segmentNumber + "] at address " + log("Skipping unloadable segment [" + segmentNumber + "] at address " +
address.toString(true) + " (size=" + fullSizeBytes + ")"); address.toString(true) + " (size=" + fullSizeBytes + ")");
return relocStart; return;
} }
try { try {
@ -2596,7 +2595,6 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
catch (AddressOverflowException e) { catch (AddressOverflowException e) {
log("Failed to load segment [" + segmentNumber + "]: " + getMessage(e)); log("Failed to load segment [" + segmentNumber + "]: " + getMessage(e));
} }
return nextRelocStart;
} }
private String getSectionComment(long addr, long byteSize, int addressableUnitSize, 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 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 * when special sections are present (e.g., __ksymtab) that we may encounter sections with
* a non-zero address. * a non-zero address.
* @param monitor * @param monitor task monitor
* @return start of relocation area * @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()) { if (!elf.isRelocatable()) {
return 0; // not applicable return 0; // not applicable
} }
@ -2664,9 +2664,7 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
AddressSpace defaultSpace = getDefaultAddressSpace(); AddressSpace defaultSpace = getDefaultAddressSpace();
ElfSectionHeader[] sections = elf.getSections(); ElfSectionHeader[] sections = elf.getSections();
for (ElfSectionHeader elfSectionToLoad : sections) { for (ElfSectionHeader elfSectionToLoad : sections) {
if (monitor.isCancelled()) { monitor.checkCanceled();
return 0;
}
long addr = elfSectionToLoad.getAddress(); long addr = elfSectionToLoad.getAddress();
if (addr < 0) { if (addr < 0) {
relocStartAddr = 0; relocStartAddr = 0;
@ -2674,9 +2672,9 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
} }
if (elfSectionToLoad.isAlloc() && addr != 0) { if (elfSectionToLoad.isAlloc() && addr != 0) {
AddressSpace loadSpace = getSectionAddressSpace(elfSectionToLoad); AddressSpace loadSpace = getSectionAddressSpace(elfSectionToLoad);
if (loadSpace.equals(defaultSpace)) { if (loadSpace.equals(space)) {
long sectionByteLength = elfSectionToLoad.getAdjustedSize(); // size in bytes long sectionByteLength = elfSectionToLoad.getAdjustedSize(); // size in bytes
long sectionLength = sectionByteLength / defaultSpace.getAddressableUnitSize(); long sectionLength = sectionByteLength / space.getAddressableUnitSize();
relocStartAddr = Math.max(relocStartAddr, addr + sectionLength); relocStartAddr = Math.max(relocStartAddr, addr + sectionLength);
} }
} }
@ -2687,26 +2685,23 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
if (testOffset != defaultSpace.getTruncatedAddress(testOffset, true).getOffset()) { if (testOffset != defaultSpace.getTruncatedAddress(testOffset, true).getOffset()) {
relocStartAddr = 0; relocStartAddr = 0;
} }
return relocStartAddr + baseOffset;
return relocStartAddr + elf.getImageBase();
} }
private void processSectionHeaders(TaskMonitor monitor) { private void processSectionHeaders(TaskMonitor monitor) throws CancelledException {
monitor.setMessage("Processing section headers..."); monitor.setMessage("Processing section headers...");
boolean includeOtherBlocks = ElfLoaderOptionsFactory.includeOtherBlocks(options); boolean includeOtherBlocks = ElfLoaderOptionsFactory.includeOtherBlocks(options);
// TODO: Use of nextRelocStart only works within default space // establish section address provider for relocatable ELF binaries
// and cause problems if used within data space - we may need to devise RelocatableImageBaseProvider relocatableImageBaseProvider = null;
// a better approach to allocating load addresses if (elf.isRelocatable()) {
long nextRelocStart = computeRelocationStartAddress(monitor); relocatableImageBaseProvider = new RelocatableImageBaseProvider(monitor);
}
ElfSectionHeader[] sections = elf.getSections(); ElfSectionHeader[] sections = elf.getSections();
for (int i = 0; i < sections.length; ++i) { for (ElfSectionHeader elfSectionToLoad : sections) {
if (monitor.isCancelled()) { monitor.checkCanceled();
return;
}
ElfSectionHeader elfSectionToLoad = sections[i];
if (elfSectionToLoad.getType() != ElfSectionHeaderConstants.SHN_UNDEF && if (elfSectionToLoad.getType() != ElfSectionHeaderConstants.SHN_UNDEF &&
(includeOtherBlocks || elfSectionToLoad.isAlloc())) { (includeOtherBlocks || elfSectionToLoad.isAlloc())) {
long fileOffset = elfSectionToLoad.getOffset(); long fileOffset = elfSectionToLoad.getOffset();
@ -2715,34 +2710,48 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
"] with invalid file offset"); "] with invalid file offset");
continue; 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 addr = elfSectionToLoad.getAddress();
long sectionByteLength = elfSectionToLoad.getAdjustedSize(); // size in bytes long sectionByteLength = elfSectionToLoad.getAdjustedSize(); // size in bytes
long loadOffset = elfSectionToLoad.getOffset(); // file offset 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) // In a relocatable ELF (object module), the address of all sections is zero.
// Therefore, we shall assign an arbitrary address that
long nextRelocStart = relocStart; // will pack the sections together with proper alignment.
// In a relocatable ELF, the address of all sections is zero.
// Therefore, we shall manufacture an arbitrary address that
// will pack the sections together.
if (elfSectionToLoad.isAlloc() && elf.isRelocatable() && addr == 0) { if (elfSectionToLoad.isAlloc() && elf.isRelocatable() && addr == 0) {
// TODO: Use of nextRelocStart only works within default space // TODO: if program headers are present (very unlikely for object module)
// and cause problems if used within data space - we may need to devise // they should be used to determine section load address since they would
// a better approach to allocating load addresses // be assigned first.
addr = NumericUtilities.getUnsignedAlignedValue(nextRelocStart, AddressSpace space = getSectionAddressSpace(elfSectionToLoad);
long relocOffset = relocatableImageBaseProvider.getNextRelocatableOffset(space);
addr = NumericUtilities.getUnsignedAlignedValue(
relocOffset,
elfSectionToLoad.getAddressAlignment()); elfSectionToLoad.getAddressAlignment());
elfSectionToLoad.setAddress(addr); elfSectionToLoad.setAddress(addr);
nextRelocStart = nextRelocOffset = addr + (sectionByteLength / space.getAddressableUnitSize());
addr + (sectionByteLength / getDefaultAddressSpace().getAddressableUnitSize());
} }
Address address = null; 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 // Check for and consume uninitialized portion of PT_LOAD segment if possible
ElfProgramHeader loadHeader = elf.getProgramLoadHeaderContaining(addr); ElfProgramHeader loadHeader = elf.getProgramLoadHeaderContaining(addr);
if (loadHeader != null) { if (loadHeader != null) {
// NOTE: should never apply to relocatable ELF
Address segmentStart = getSegmentLoadAddress(loadHeader); Address segmentStart = getSegmentLoadAddress(loadHeader);
AddressSpace segmentSpace = segmentStart.getAddressSpace(); AddressSpace segmentSpace = segmentStart.getAddressSpace();
long loadSizeBytes = loadHeader.getAdjustedLoadSize(); long loadSizeBytes = loadHeader.getAdjustedLoadSize();
@ -2772,7 +2782,7 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
if (sectionByteLength == 0) { if (sectionByteLength == 0) {
log("Skipping empty section [" + elfSectionToLoad.getNameAsString() + "]"); log("Skipping empty section [" + elfSectionToLoad.getNameAsString() + "]");
return relocStart; return;
} }
if (address == null) { if (address == null) {
@ -2783,7 +2793,7 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
if (!space.isValidRange(address.getOffset(), sectionByteLength)) { if (!space.isValidRange(address.getOffset(), sectionByteLength)) {
log("Skipping unloadable section [" + elfSectionToLoad.getNameAsString() + log("Skipping unloadable section [" + elfSectionToLoad.getNameAsString() +
"] at address " + address.toString(true) + " (size=" + sectionByteLength + ")"); "] at address " + address.toString(true) + " (size=" + sectionByteLength + ")");
return relocStart; return;
} }
final String blockName = elfSectionToLoad.getNameAsString(); final String blockName = elfSectionToLoad.getNameAsString();
@ -2793,7 +2803,7 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
elfSectionToLoad.getType() == ElfSectionHeaderConstants.SHT_NOBITS) { elfSectionToLoad.getType() == ElfSectionHeaderConstants.SHT_NOBITS) {
if (!elfSectionToLoad.isAlloc() && if (!elfSectionToLoad.isAlloc() &&
elfSectionToLoad.getType() != ElfSectionHeaderConstants.SHT_PROGBITS) { elfSectionToLoad.getType() != ElfSectionHeaderConstants.SHT_PROGBITS) {
return nextRelocStart; // non-allocate at runtime return; // non-allocate at runtime
} }
String comment = String comment =
getSectionComment(addr, sectionByteLength, space.getAddressableUnitSize(), getSectionComment(addr, sectionByteLength, space.getAddressableUnitSize(),
@ -2815,8 +2825,10 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
log("Failed to load section [" + elfSectionToLoad.getNameAsString() + "]: " + log("Failed to load section [" + elfSectionToLoad.getNameAsString() + "]: " +
getMessage(e)); getMessage(e));
} }
return nextRelocStart; if (nextRelocOffset != null) {
relocatableImageBaseProvider.setNextRelocatableOffset(space, nextRelocOffset);
}
} }
private String pad(int value) { private String pad(int value) {
@ -3009,4 +3021,32 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
revisedLength, comment, BLOCK_SOURCE_NAME, r, w, x, log); revisedLength, comment, BLOCK_SOURCE_NAME, r, w, x, log);
} }
private class RelocatableImageBaseProvider {
Map<Integer, Long> 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;
}
}
} }

View file

@ -563,12 +563,16 @@ public class ImporterDialog extends DialogComponentProvider {
} }
private LanguageCompilerSpecPair getPreferredLanguage(Loader loader) { private LanguageCompilerSpecPair getPreferredLanguage(Loader loader) {
LanguageCompilerSpecPair preferredSpecPair = null;
for (LoadSpec loadSpec : loaderMap.get(loader)) { for (LoadSpec loadSpec : loaderMap.get(loader)) {
if (loadSpec.isPreferred()) { if (loadSpec.isPreferred()) {
return loadSpec.getLanguageCompilerSpec(); if (preferredSpecPair != null) {
return null;
}
preferredSpecPair = loadSpec.getLanguageCompilerSpec();
} }
} }
return null; return preferredSpecPair;
} }
private DomainFolder getProjectRootFolder() { private DomainFolder getProjectRootFolder() {

View file

@ -265,22 +265,6 @@ public class SleighLanguage implements Language {
return getRegisterManager().getContextBaseRegister(); return getRegisterManager().getContextBaseRegister();
} }
@Override
public List<AddressLabelInfo> getDefaultLabels() {
ArrayList<AddressLabelInfo> 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 @Override
public MemoryBlockDefinition[] getDefaultMemoryBlocks() { public MemoryBlockDefinition[] getDefaultMemoryBlocks() {
return defaultMemoryBlocks; return defaultMemoryBlocks;

View file

@ -119,4 +119,15 @@ public final class GhidraLanguagePropertyKeys {
* NOTE: This is an experimental concept which may be removed in the future * NOTE: This is an experimental concept which may be removed in the future
*/ */
public static final String RESET_CONTEXT_ON_UPGRADE = "resetContextOnUpgrade"; 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: <code>Data Image Base</code>.
*/
public static final String MINIMUM_DATA_IMAGE_BASE = "minimumDataImageBase";
} }

View file

@ -226,13 +226,6 @@ public interface Language {
*/ */
public Register getRegister(Address addr, int size); 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<AddressLabelInfo> getDefaultLabels();
/** /**
* Get the default program counter register for this language if there is * Get the default program counter register for this language if there is
* one. * one.
@ -254,7 +247,8 @@ public interface Language {
public MemoryBlockDefinition[] getDefaultMemoryBlocks(); 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 * @return the default symbols for this language
*/ */
public List<AddressLabelInfo> getDefaultSymbols(); public List<AddressLabelInfo> getDefaultSymbols();

View file

@ -585,11 +585,6 @@ class OldLanguage implements Language {
return null; return null;
} }
@Override
public List<AddressLabelInfo> getDefaultLabels() {
throw new UnsupportedOperationException("Language for upgrade use only (getDefaultLabels)");
}
@Override @Override
public Register getProgramCounter() { public Register getProgramCounter() {
throw new UnsupportedOperationException( throw new UnsupportedOperationException(

View file

@ -9,6 +9,8 @@ data/languages/PIC24.sinc||GHIDRA||||END|
data/languages/PIC24E.slaspec||GHIDRA||reviewed||END| data/languages/PIC24E.slaspec||GHIDRA||reviewed||END|
data/languages/PIC24F.slaspec||GHIDRA||reviewed||END| data/languages/PIC24F.slaspec||GHIDRA||reviewed||END|
data/languages/PIC24H.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/dsPIC30F.slaspec||GHIDRA||reviewed||END|
data/languages/dsPIC33C.slaspec||GHIDRA||||END| data/languages/dsPIC33C.slaspec||GHIDRA||||END|
data/languages/dsPIC33E.slaspec||GHIDRA||reviewed||END| data/languages/dsPIC33E.slaspec||GHIDRA||reviewed||END|

View file

@ -48,6 +48,7 @@
id="dsPIC30F:LE:24:default"> id="dsPIC30F:LE:24:default">
<description>dsPIC30F</description> <description>dsPIC30F</description>
<compiler name="default" spec="PIC24.cspec" id="default"/> <compiler name="default" spec="PIC24.cspec" id="default"/>
<external_name tool="DWARF.register.mapping.file" name="PIC30.dwarf"/>
</language> </language>
<language processor="dsPIC33F" <language processor="dsPIC33F"
endian="little" endian="little"
@ -60,6 +61,7 @@
id="dsPIC33F:LE:24:default"> id="dsPIC33F:LE:24:default">
<description>dsPIC33F</description> <description>dsPIC33F</description>
<compiler name="default" spec="PIC24.cspec" id="default"/> <compiler name="default" spec="PIC24.cspec" id="default"/>
<external_name tool="DWARF.register.mapping.file" name="PIC30.dwarf"/>
</language> </language>
<language processor="dsPIC33E" <language processor="dsPIC33E"
endian="little" endian="little"
@ -72,6 +74,7 @@
id="dsPIC33E:LE:24:default"> id="dsPIC33E:LE:24:default">
<description>dsPIC33E</description> <description>dsPIC33E</description>
<compiler name="default" spec="PIC24.cspec" id="default"/> <compiler name="default" spec="PIC24.cspec" id="default"/>
<external_name tool="DWARF.register.mapping.file" name="PIC33.dwarf"/>
</language> </language>
<language processor="dsPIC33C" <language processor="dsPIC33C"
endian="little" endian="little"
@ -84,5 +87,6 @@
id="dsPIC33C:LE:24:default"> id="dsPIC33C:LE:24:default">
<description>dsPIC33C</description> <description>dsPIC33C</description>
<compiler name="default" spec="PIC24.cspec" id="default"/> <compiler name="default" spec="PIC24.cspec" id="default"/>
<external_name tool="DWARF.register.mapping.file" name="PIC33.dwarf"/>
</language> </language>
</language_definitions> </language_definitions>

View file

@ -4,7 +4,10 @@
</constraint> </constraint>
<constraint loader="Executable and Linking Format (ELF)" compilerSpecID="default"> <constraint loader="Executable and Linking Format (ELF)" compilerSpecID="default">
<!-- Elf treats as 32-bit while our definition indicates 24-bit --> <!-- Elf treats as 32-bit while our definition indicates 24-bit -->
<constraint primary="118" processor="dsPIC30F" endian="little" /> <constraint primary="118" processor="dsPIC30F" endian="little" />
<constraint primary="118" processor="dsPIC33E" endian="little" />
<constraint primary="118" processor="dsPIC33C" endian="little" />
<constraint primary="118" processor="dsPIC33F" endian="little" />
</constraint> </constraint>
<constraint loader="Common Object File Format (COFF)" compilerSpecID="default"> <constraint loader="Common Object File Format (COFF)" compilerSpecID="default">
<constraint primary="4662" processor="dsPIC30F" endian="little" /> <constraint primary="4662" processor="dsPIC30F" endian="little" />

View file

@ -3,8 +3,8 @@
<processor_spec> <processor_spec>
<properties> <properties>
<property key="assemblyRating:dsPIC30F:LE:24:default" value="POOR"/> <property key="assemblyRating:dsPIC30F:LE:24:default" value="POOR"/>
<property key="assemblyMessage:dsPIC30F:LE:24:default" <property key="assemblyMessage:dsPIC30F:LE:24:default" value="The language tested with a rating of POOR; however, the failures all deal with extraneous instructions. The assembler may offer you several options. At least one of them will be correct, but others may be erroneous."/>
value="The language tested with a rating of POOR; however, the failures all deal with extraneous instructions. The assembler may offer you several options. At least one of them will be correct, but others may be erroneous."/> <property key="minimumDataImageBase" value="0x1000" />
</properties> </properties>
<programcounter register="PC"/> <programcounter register="PC"/>
<data_space space="ram"/> <data_space space="ram"/>

View file

@ -806,10 +806,10 @@ f13byte_t: TOK_f13 is TOK_B=1 & TOK_f13
{ export *[ram]:1 TOK_f13; } { export *[ram]:1 TOK_f13; }
f15_t: addr is TOK_f15 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 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 k3_t: "#"TOK_k3 is TOK_k3
{ export *[const]:1 TOK_k3; } { export *[const]:1 TOK_k3; }
@ -3992,6 +3992,8 @@ define pcodeop pic30_rem2;
Wnd_t = -shift; 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 { :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); 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 { :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 @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 { :xor.w f13_t^WREG_t is OP_23_20=0xB & OP_19_16=0x6 & OP_15=1 & WREG_t & f13_t {

View file

@ -0,0 +1,21 @@
<dwarf>
<register_mappings>
<register_mapping dwarf="0" ghidra="W0" auto_count="15"/> <!-- W0..W14 -->
<register_mapping dwarf="15" ghidra="W15" stackpointer="true"/>
<register_mapping dwarf="16" ghidra="RCOUNT"/>
<register_mapping dwarf="17" ghidra="ACCA"/>
<register_mapping dwarf="18" ghidra="ACCB"/>
<register_mapping dwarf="19" ghidra="PSVPAG"/>
<!-- <register_mapping dwarf="20" ghidra="PMADDR"/> **not implemented** -->
<!-- <register_mapping dwarf="21" ghidra="PMMODE"/> **not implemented** -->
<!-- <register_mapping dwarf="22" ghidra="PMDIN1"/> **not implemented** -->
<!-- <register_mapping dwarf="23" ghidra="PMDIN2"/> **not implemented** -->
<!-- <register_mapping dwarf="24" ghidra="DSWPAG"/> **not implemented** -->
<!-- <register_mapping dwarf="25" ghidra="SINK0" auto_count="8"/> **not implemented** -->
</register_mappings>
<call_frame_cfa value="4"/>
</dwarf>

View file

@ -0,0 +1,21 @@
<dwarf>
<register_mappings>
<register_mapping dwarf="0" ghidra="W0" auto_count="15"/> <!-- W0..W14 -->
<register_mapping dwarf="15" ghidra="W15" stackpointer="true"/>
<register_mapping dwarf="16" ghidra="RCOUNT"/>
<register_mapping dwarf="17" ghidra="ACCA"/>
<register_mapping dwarf="18" ghidra="ACCB"/>
<register_mapping dwarf="19" ghidra="DSRPAG"/>
<!-- <register_mapping dwarf="20" ghidra="PMADDR"/> **not implemented** -->
<!-- <register_mapping dwarf="21" ghidra="PMMODE"/> **not implemented** -->
<!-- <register_mapping dwarf="22" ghidra="PMDIN1"/> **not implemented** -->
<!-- <register_mapping dwarf="23" ghidra="PMDIN2"/> **not implemented** -->
<register_mapping dwarf="24" ghidra="DSWPAG"/>
<!-- <register_mapping dwarf="25" ghidra="SINK0" auto_count="8"/> **not implemented** -->
</register_mappings>
<call_frame_cfa value="4"/>
</dwarf>

View file

@ -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;
}
}

View file

@ -29,7 +29,61 @@ public class PIC30_ElfExtension extends ElfExtension {
public static final int EM_DSPIC30F = 118; /* Microchip Technology dsPIC30F DSC */ 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_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 @Override
public boolean canHandle(ElfHeader elf) { public boolean canHandle(ElfHeader elf) {
@ -84,11 +138,30 @@ public class PIC30_ElfExtension extends ElfExtension {
private boolean isDataLoad(ElfSectionHeader section) { private boolean isDataLoad(ElfSectionHeader section) {
if (!section.isAlloc()) { if (!section.isAlloc()) {
return false; return isDebugSection(section);
} }
return !section.isExecutable(); 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 @Override
public long getAdjustedLoadSize(ElfProgramHeader elfProgramHeader) { public long getAdjustedLoadSize(ElfProgramHeader elfProgramHeader) {
long fileSize = elfProgramHeader.getFileSize(); long fileSize = elfProgramHeader.getFileSize();
@ -111,48 +184,60 @@ public class PIC30_ElfExtension extends ElfExtension {
public InputStream getFilteredLoadInputStream(ElfLoadHelper elfLoadHelper, public InputStream getFilteredLoadInputStream(ElfLoadHelper elfLoadHelper,
MemoryLoadable loadable, Address start, long dataLength, InputStream dataInput) { MemoryLoadable loadable, Address start, long dataLength, InputStream dataInput) {
Language language = elfLoadHelper.getProgram().getLanguage(); Language language = elfLoadHelper.getProgram().getLanguage();
if (!language.getDefaultDataSpace().equals(start.getAddressSpace().getPhysicalSpace())) { if (!isDataLoad(loadable) && !language.getDefaultDataSpace().equals(start.getAddressSpace().getPhysicalSpace())) {
return dataInput; return dataInput;
} }
if (loadable instanceof ElfSectionHeader) { if (loadable instanceof ElfSectionHeader) {
ElfSectionHeader section = (ElfSectionHeader) loadable; 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 // 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 // In the absence of suitable mapping, we will load into RAM space
return new PIC30FilteredPSVDataInputStream(dataInput); return new PIC30FilteredPSVDataInputStream(dataInput);
} }
} }
else {
return new PIC30FilteredPSVDataInputStream(dataInput);
}
// Data space loading pads after every byte with Microchip toolchain // Data space loading pads after every byte with Microchip toolchain
// NOTE: this could vary and we may need to improve detection of this situation // 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 @Override
public boolean hasFilteredLoadInputStream(ElfLoadHelper elfLoadHelper, MemoryLoadable loadable, public boolean hasFilteredLoadInputStream(ElfLoadHelper elfLoadHelper, MemoryLoadable loadable,
Address start) { Address start) {
if (loadable == null) {
return false;
}
if (isDataLoad(loadable)) {
return true;
}
Language language = elfLoadHelper.getProgram().getLanguage(); Language language = elfLoadHelper.getProgram().getLanguage();
return language.getDefaultDataSpace().equals(start.getAddressSpace().getPhysicalSpace()); return language.getDefaultDataSpace().equals(start.getAddressSpace().getPhysicalSpace());
} }
private static class PIC30FilteredDataInputStream extends FilterInputStream { private static class PIC30FilteredDataInputStream extends FilterInputStream {
// BYTES: <byte> <pad> // BYTES: <byte> <pad>
protected boolean padByteToggle; protected boolean padByteToggle;
protected long pos; protected long pos;
protected PIC30FilteredDataInputStream(InputStream in) { private final boolean checkPadding;
protected PIC30FilteredDataInputStream(InputStream in, boolean checkPadding) {
super(in); super(in);
padByteToggle = false; // first byte is data not padding padByteToggle = false; // first byte is data not padding
this.checkPadding = checkPadding;
} }
protected int readNextByte() throws IOException { protected int readNextByte() throws IOException {
int r = in.read(); int r = in.read();
if (padByteToggle && r != 0) { if (checkPadding && padByteToggle && r != 0) {
// expected padding // expected padding - debug sections appear to be inconsistent with filler
throw new IOException("expected Data padding byte, pos=" + pos); throw new IOException("expected Data padding byte, pos=" + pos);
} }
++pos; ++pos;
@ -204,7 +289,7 @@ public class PIC30_ElfExtension extends ElfExtension {
private boolean firstByteToggle; // firstByte of data or pad private boolean firstByteToggle; // firstByte of data or pad
protected PIC30FilteredPSVDataInputStream(InputStream in) { protected PIC30FilteredPSVDataInputStream(InputStream in) {
super(in); super(in, true);
firstByteToggle = true; firstByteToggle = true;
} }

View file

@ -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<ElfSymbol, Address> 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);
}
}

View file

@ -15,8 +15,11 @@
*/ */
package ghidra.app.util.bin.format.elf.relocation; package ghidra.app.util.bin.format.elf.relocation;
import java.util.Map;
import ghidra.app.util.bin.format.elf.*; import ghidra.app.util.bin.format.elf.*;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.lang.Register;
import ghidra.program.model.listing.Program; import ghidra.program.model.listing.Program;
import ghidra.program.model.mem.Memory; import ghidra.program.model.mem.Memory;
import ghidra.program.model.mem.MemoryAccessException; import ghidra.program.model.mem.MemoryAccessException;
@ -24,16 +27,78 @@ import ghidra.util.exception.NotFoundException;
public class PIC30_ElfRelocationHandler extends ElfRelocationHandler { 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_NONE = 0;
public static final int R_PIC30_8 = 1; public static final int R_PIC30_8 = 1;
public static final int R_PIC30_16 = 2; public static final int R_PIC30_16 = 2;
public static final int R_PIC30_32 = 3; 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_FILE_REG_WORD_WITH_DST = 7;
public static final int R_PIC30_WORD = 8; 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_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 @Override
public boolean canRelocate(ElfHeader elf) { public boolean canRelocate(ElfHeader elf) {
@ -41,8 +106,24 @@ public class PIC30_ElfRelocationHandler extends ElfRelocationHandler {
} }
@Override @Override
public void relocate(ElfRelocationContext elfRelocationContext, ElfRelocation relocation, public PIC30_ElfRelocationContext createRelocationContext(ElfLoadHelper loadHelper,
Address relocationAddress) throws MemoryAccessException, NotFoundException { ElfRelocationTable relocationTable, Map<ElfSymbol, Address> 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(); int type = relocation.getType();
if (type == R_PIC30_NONE) { if (type == R_PIC30_NONE) {
@ -54,57 +135,71 @@ public class PIC30_ElfRelocationHandler extends ElfRelocationHandler {
int symbolIndex = relocation.getSymbolIndex(); 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; return;
} }
long offset = (int) relocationAddress.getOffset(); long relocWordOffset = (int) relocationAddress.getAddressableWordOffset();
ElfSymbol sym = elfRelocationContext.getSymbol(symbolIndex); ElfSymbol sym = elfRelocationContext.getSymbol(symbolIndex);
long symbolValue = elfRelocationContext.getSymbolValue(sym); int symbolValue = (int) elfRelocationContext.getSymbolValue(sym); // word offset
int oldValue = memory.getInt(relocationAddress); int oldValue = memory.getInt(relocationAddress);
short oldShortValue = memory.getShort(relocationAddress);
int newValue; int newValue;
ElfHeader elf = elfRelocationContext.getElfHeader(); 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) { switch (type) {
case R_PIC30_32: case R_PIC30_16: // 2
newValue = (((int) symbolValue + (int) addend + oldValue) & 0xffffffff); newValue = (symbolValue + addend + oldShortValue) & 0xffff;
memory.setInt(relocationAddress, newValue); memory.setShort(relocationAddress, (short) newValue);
break; break;
case R_PIC30_PCREL_BRANCH: case R_PIC30_32: // 3
int offsetValue = memory.getShort(relocationAddress) + 1; newValue = symbolValue + addend + oldValue;
offsetValue = offsetValue * 2; // make it byte oriented - this should normally be 0 memory.setInt(relocationAddress, newValue);
newValue = (int) (((symbolValue + (int) addend - (offset + 4)))); break;
newValue >>>= 2; // turn it into word offset, and align to even address, actually an error if it isn't aligned case R_PIC30_FILE_REG_WORD_WITH_DST: // 7
// work it into the instruction int reloc = symbolValue >> 1;
memory.setShort(relocationAddress, (short) (newValue & 0xffff)); reloc += addend;
break; reloc += oldValue >> 4;
case R_PIC30_16: reloc &= 0x7fff;
short oldShortValue = memory.getShort(relocationAddress); newValue = (reloc << 4) | (oldValue & ~0x7fff0);
newValue = ((((int) symbolValue + (int) addend + oldShortValue) >> 1) & 0xffff); memory.setInt(relocationAddress, newValue);
memory.setShort(relocationAddress, (short) newValue); break;
break; case R_PIC30_WORD: // 8
case R_PIC30_FILE_REG_WORD_WITH_DST: case R_PIC30_WORD_TBLOFFSET: // 0x15
newValue = ((((int) symbolValue + (int) addend) >> 1) & 0x7fff); reloc = symbolValue;
int dst = (oldValue >> 4) & 0x7fff; reloc += addend;
newValue = ((newValue + dst) << 4) | (oldValue & 0xfff1000f); reloc += oldValue >> 4;
memory.setInt(relocationAddress, newValue); reloc &= 0xffff;
break; newValue = (reloc << 4) | (oldValue & ~0x0ffff0);
case R_PIC30_WORD: memory.setInt(relocationAddress, newValue);
newValue = ((((int) symbolValue + (int) addend) >> 1) & 0xffff); break;
newValue = (newValue << 4) | oldValue; case R_PIC30_WORD_TBLPAGE: // 0x18
memory.setInt(relocationAddress, newValue); reloc = symbolValue >> 16;
break; reloc += addend;
case R_PIC30_8: reloc += oldValue >> 4;
default: reloc &= 0xffff;
String symbolName = sym.getNameAsString(); if (isEDSVariant(elfRelocationContext)) {
markAsUnhandled(program, relocationAddress, type, symbolIndex, symbolName, 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()); elfRelocationContext.getLog());
break; break;
} }
} }
} }

View file

@ -589,6 +589,7 @@ The Headless Analyzer uses the command-line parameters discussed below. See <a h
<LI><typewriter>-loader-loadExternalLibs &lt;true|false&gt;</typewriter></LI> <LI><typewriter>-loader-loadExternalLibs &lt;true|false&gt;</typewriter></LI>
<LI><typewriter>-loader-applyRelocations &lt;true|false&gt;</typewriter></LI> <LI><typewriter>-loader-applyRelocations &lt;true|false&gt;</typewriter></LI>
<LI><typewriter>-loader-imagebase &lt;imagebase<sup>3</sup>&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> <LI><typewriter>-loader-includeOtherBlocks &lt;true|false&gt;</typewriter></LI>
<LI><typewriter>-loader-resolveExternalSymbols &lt;true|false&gt;</typewriter></LI> <LI><typewriter>-loader-resolveExternalSymbols &lt;true|false&gt;</typewriter></LI>
</UL> </UL>
@ -609,9 +610,11 @@ The Headless Analyzer uses the command-line parameters discussed below. See <a h
</UL> </UL>
</UL> </UL>
<br> <br>
<sup>1. Address must be in the form [space:]offset. Space is optional, and offset is a hex value with no leading 0x.</sup><br> <sup>1</sup>Address must be in the form [space:]offset. Space is optional, and offset is a hex value with no leading 0x.<br>
<sup>2. To specify hexadecimal, use a leading 0x.</sup><br> <sup>2</sup>To specify hexadecimal, use a leading 0x.<br>
<sup>3. Address is in the default space, and must be specified as a hexadecimal value without the leading 0x.</sup><br> <sup>3</sup>Base address is in the default space and must be specified as a hexadecimal value without the leading 0x.<br>
<sup>4</sup>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).<br>
</LI> </LI>
</UL> </UL>