mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 02:39:44 +02:00
Merge branch 'ghidra1_PIC30_ElfImportFixes'
This commit is contained in:
commit
305a1ddf98
28 changed files with 904 additions and 317 deletions
|
@ -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. Overlay blocks can serve various
|
overlay address space. Overlay blocks can serve various
|
||||||
purposes where a memory range may contain different data/code or map to different areas of memory
|
purposes where a memory range may contain different data/code or map to different areas of memory
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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";
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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|
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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" />
|
||||||
|
|
|
@ -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"/>
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
||||||
|
|
21
Ghidra/Processors/PIC/data/languages/PIC30.dwarf
Normal file
21
Ghidra/Processors/PIC/data/languages/PIC30.dwarf
Normal 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>
|
21
Ghidra/Processors/PIC/data/languages/PIC33.dwarf
Normal file
21
Ghidra/Processors/PIC/data/languages/PIC33.dwarf
Normal 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>
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -589,6 +589,7 @@ The Headless Analyzer uses the command-line parameters discussed below. See <a h
|
||||||
<LI><typewriter>-loader-loadExternalLibs <true|false></typewriter></LI>
|
<LI><typewriter>-loader-loadExternalLibs <true|false></typewriter></LI>
|
||||||
<LI><typewriter>-loader-applyRelocations <true|false></typewriter></LI>
|
<LI><typewriter>-loader-applyRelocations <true|false></typewriter></LI>
|
||||||
<LI><typewriter>-loader-imagebase <imagebase<sup>3</sup>></typewriter></LI>
|
<LI><typewriter>-loader-imagebase <imagebase<sup>3</sup>></typewriter></LI>
|
||||||
|
<LI><typewriter>-loader-dataImageBase <dataImageBase<sup>4</sup>></typewriter></LI>
|
||||||
<LI><typewriter>-loader-includeOtherBlocks <true|false></typewriter></LI>
|
<LI><typewriter>-loader-includeOtherBlocks <true|false></typewriter></LI>
|
||||||
<LI><typewriter>-loader-resolveExternalSymbols <true|false></typewriter></LI>
|
<LI><typewriter>-loader-resolveExternalSymbols <true|false></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>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue