mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 09:49:23 +02:00
Merge remote-tracking branch 'origin/Ghidra_11.4'
This commit is contained in:
commit
33b9688d7c
15 changed files with 138 additions and 121 deletions
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -43,9 +43,10 @@ public final class DyldInfoCommandConstants {
|
||||||
public final static int BIND_TYPE_TEXT_ABSOLUTE32 = 2;
|
public final static int BIND_TYPE_TEXT_ABSOLUTE32 = 2;
|
||||||
public final static int BIND_TYPE_TEXT_PCREL32 = 3;
|
public final static int BIND_TYPE_TEXT_PCREL32 = 3;
|
||||||
|
|
||||||
public final static int BIND_SPECIAL_DYLIB_SELF = 0;
|
public final static int BIND_SPECIAL_DYLIB_SELF = 0;
|
||||||
public final static int BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE = -1;
|
public final static int BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE = -1;
|
||||||
public final static int BIND_SPECIAL_DYLIB_FLAT_LOOKUP = -2;
|
public final static int BIND_SPECIAL_DYLIB_FLAT_LOOKUP = -2;
|
||||||
|
public final static int BIND_SPECIAL_DYLIB_WEAK_LOOKUP = -3;
|
||||||
|
|
||||||
public final static int BIND_SYMBOL_FLAGS_WEAK_IMPORT = 0x1;
|
public final static int BIND_SYMBOL_FLAGS_WEAK_IMPORT = 0x1;
|
||||||
public final static int BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION = 0x8;
|
public final static int BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION = 0x8;
|
||||||
|
|
|
@ -28,15 +28,15 @@ import ghidra.app.util.opinion.MachoProgramBuilder;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
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.reloc.Relocation.Status;
|
import ghidra.program.model.reloc.Relocation.Status;
|
||||||
import ghidra.program.model.symbol.Symbol;
|
import ghidra.program.model.symbol.*;
|
||||||
import ghidra.program.model.symbol.SymbolTable;
|
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.CancelledException;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
public class DyldChainedFixups {
|
public class DyldChainedFixups {
|
||||||
|
|
||||||
|
public static final int RELOCATION_TYPE = 0x8888;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Walks the chained fixup information and collects a {@link List} of {@link DyldFixup}s that
|
* Walks the chained fixup information and collects a {@link List} of {@link DyldFixup}s that
|
||||||
* will need to be applied to the image
|
* will need to be applied to the image
|
||||||
|
@ -67,10 +67,10 @@ public class DyldChainedFixups {
|
||||||
|
|
||||||
long chainLoc = page + nextOff;
|
long chainLoc = page + nextOff;
|
||||||
final long chainValue = DyldChainedPtr.getChainValue(reader, chainLoc, pointerFormat);
|
final long chainValue = DyldChainedPtr.getChainValue(reader, chainLoc, pointerFormat);
|
||||||
long newChainValue = chainValue;
|
Long newChainValue = chainValue;
|
||||||
boolean isAuthenticated = DyldChainedPtr.isAuthenticated(pointerFormat, chainValue);
|
boolean isAuthenticated = DyldChainedPtr.isAuthenticated(pointerFormat, chainValue);
|
||||||
boolean isBound = DyldChainedPtr.isBound(pointerFormat, chainValue);
|
boolean isBound = DyldChainedPtr.isBound(pointerFormat, chainValue);
|
||||||
Symbol symbol = null;
|
String symbol = null;
|
||||||
Integer libOrdinal = null;
|
Integer libOrdinal = null;
|
||||||
|
|
||||||
if (isBound) {
|
if (isBound) {
|
||||||
|
@ -88,13 +88,16 @@ public class DyldChainedFixups {
|
||||||
int chainOrdinal = (int) DyldChainedPtr.getOrdinal(pointerFormat, chainValue);
|
int chainOrdinal = (int) DyldChainedPtr.getOrdinal(pointerFormat, chainValue);
|
||||||
long addend = DyldChainedPtr.getAddend(pointerFormat, chainValue);
|
long addend = DyldChainedPtr.getAddend(pointerFormat, chainValue);
|
||||||
DyldChainedImport chainedImport = chainedImports.getChainedImport(chainOrdinal);
|
DyldChainedImport chainedImport = chainedImports.getChainedImport(chainOrdinal);
|
||||||
List<Symbol> globalSymbols = symbolTable.getGlobalSymbols(chainedImport.getName());
|
symbol = SymbolUtilities.replaceInvalidChars(chainedImport.getName(), true);
|
||||||
|
libOrdinal = chainedImport.getLibOrdinal();
|
||||||
|
List<Symbol> globalSymbols = symbolTable.getGlobalSymbols(symbol);
|
||||||
if (globalSymbols.size() > 0) {
|
if (globalSymbols.size() > 0) {
|
||||||
symbol = globalSymbols.get(0);
|
newChainValue = globalSymbols.getFirst().getAddress().getOffset();
|
||||||
newChainValue = symbol.getAddress().getOffset();
|
newChainValue += isAuthenticated ? auth_value_add : addend;
|
||||||
libOrdinal = chainedImport.getLibOrdinal();
|
}
|
||||||
|
else {
|
||||||
|
newChainValue = null;
|
||||||
}
|
}
|
||||||
newChainValue += isAuthenticated ? auth_value_add : addend;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (isAuthenticated) {
|
if (isAuthenticated) {
|
||||||
|
@ -110,7 +113,7 @@ public class DyldChainedFixups {
|
||||||
}
|
}
|
||||||
|
|
||||||
fixups.add(new DyldFixup(chainLoc, newChainValue, DyldChainedPtr.getSize(pointerFormat),
|
fixups.add(new DyldFixup(chainLoc, newChainValue, DyldChainedPtr.getSize(pointerFormat),
|
||||||
symbol != null ? symbol.getName() : null, libOrdinal));
|
symbol, libOrdinal));
|
||||||
|
|
||||||
next = DyldChainedPtr.getNext(pointerFormat, chainValue);
|
next = DyldChainedPtr.getNext(pointerFormat, chainValue);
|
||||||
nextOff += next * DyldChainedPtr.getStride(pointerFormat);
|
nextOff += next * DyldChainedPtr.getStride(pointerFormat);
|
||||||
|
@ -128,12 +131,11 @@ public class DyldChainedFixups {
|
||||||
* @param log The log
|
* @param log The log
|
||||||
* @param monitor A cancellable monitor
|
* @param monitor A cancellable monitor
|
||||||
* @return A {@link List} of fixed up {@link Address}'s
|
* @return A {@link List} of fixed up {@link Address}'s
|
||||||
* @throws MemoryAccessException If there was a problem accessing memory
|
|
||||||
* @throws CancelledException If the user cancelled the operation
|
* @throws CancelledException If the user cancelled the operation
|
||||||
*/
|
*/
|
||||||
public static List<Address> fixupChainedPointers(List<DyldFixup> fixups, Program program,
|
public static List<Address> fixupChainedPointers(List<DyldFixup> fixups, Program program,
|
||||||
Address imagebase, List<String> libraryPaths, MessageLog log, TaskMonitor monitor)
|
Address imagebase, List<String> libraryPaths, MessageLog log, TaskMonitor monitor)
|
||||||
throws MemoryAccessException, CancelledException {
|
throws CancelledException {
|
||||||
List<Address> fixedAddrs = new ArrayList<>();
|
List<Address> fixedAddrs = new ArrayList<>();
|
||||||
if (fixups.isEmpty()) {
|
if (fixups.isEmpty()) {
|
||||||
return fixedAddrs;
|
return fixedAddrs;
|
||||||
|
@ -142,37 +144,42 @@ public class DyldChainedFixups {
|
||||||
monitor.initialize(fixups.size(), "Fixing up chained pointers...");
|
monitor.initialize(fixups.size(), "Fixing up chained pointers...");
|
||||||
for (DyldFixup fixup : fixups) {
|
for (DyldFixup fixup : fixups) {
|
||||||
monitor.increment();
|
monitor.increment();
|
||||||
Status status = Status.FAILURE;
|
Status status = Status.UNSUPPORTED;
|
||||||
Address addr = imagebase.add(fixup.offset());
|
Address addr = imagebase.add(fixup.offset());
|
||||||
|
String symbol = fixup.symbol();
|
||||||
|
long[] value = new long[] {};
|
||||||
try {
|
try {
|
||||||
if (fixup.size() == 8 || fixup.size() == 4) {
|
if (fixup.value() != null) {
|
||||||
if (fixup.size() == 8) {
|
if (fixup.size() == 8 || fixup.size() == 4) {
|
||||||
memory.setLong(addr, fixup.value());
|
if (fixup.size() == 8) {
|
||||||
|
memory.setLong(addr, fixup.value());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
memory.setInt(addr, fixup.value().intValue());
|
||||||
|
}
|
||||||
|
fixedAddrs.add(addr);
|
||||||
|
status = Status.APPLIED_OTHER;
|
||||||
}
|
}
|
||||||
else {
|
value = new long[] { fixup.value() };
|
||||||
memory.setInt(addr, (int) fixup.value());
|
}
|
||||||
|
if (symbol != null && fixup.libOrdinal() != null) {
|
||||||
|
value = new long[] { fixup.libOrdinal() };
|
||||||
|
try {
|
||||||
|
MachoProgramBuilder.fixupExternalLibrary(program, libraryPaths,
|
||||||
|
fixup.libOrdinal(), symbol);
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
log.appendMsg("WARNING: Problem fixing up symbol '%s' - %s"
|
||||||
|
.formatted(symbol, e.getMessage()));
|
||||||
}
|
}
|
||||||
fixedAddrs.add(addr);
|
|
||||||
status = Status.APPLIED_OTHER;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
status = Status.UNSUPPORTED;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
status = Status.FAILURE;
|
||||||
|
}
|
||||||
finally {
|
finally {
|
||||||
program.getRelocationTable()
|
program.getRelocationTable()
|
||||||
.add(addr, status, 0, new long[] { fixup.value() }, fixup.size(),
|
.add(addr, status, RELOCATION_TYPE, value, fixup.size(), symbol);
|
||||||
fixup.symbol() != null ? fixup.symbol() : null);
|
|
||||||
}
|
|
||||||
if (fixup.symbol() != null && fixup.libOrdinal() != null) {
|
|
||||||
try {
|
|
||||||
MachoProgramBuilder.fixupExternalLibrary(program, libraryPaths,
|
|
||||||
fixup.libOrdinal(), fixup.symbol());
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
log.appendMsg("WARNING: Problem fixing up symbol '%s' - %s"
|
|
||||||
.formatted(fixup.symbol(), e.getMessage()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
log.appendMsg("Fixed up " + fixedAddrs.size() + " chained pointers.");
|
log.appendMsg("Fixed up " + fixedAddrs.size() + " chained pointers.");
|
||||||
|
|
|
@ -47,14 +47,16 @@ public class DyldChainedImport implements StructConverter {
|
||||||
switch (imports_format) {
|
switch (imports_format) {
|
||||||
case DYLD_CHAINED_IMPORT: {
|
case DYLD_CHAINED_IMPORT: {
|
||||||
int ival = reader.readNextInt();
|
int ival = reader.readNextInt();
|
||||||
lib_ordinal = ival & 0xff;
|
int ordinal = ival & 0xff;
|
||||||
|
lib_ordinal = ordinal > 0xf0 ? (byte) ordinal : ordinal;
|
||||||
weak_import = ((ival >> 8) & 1) == 1;
|
weak_import = ((ival >> 8) & 1) == 1;
|
||||||
name_offset = (ival >> 9 & 0x7fffff);
|
name_offset = (ival >> 9 & 0x7fffff);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DYLD_CHAINED_IMPORT_ADDEND: {
|
case DYLD_CHAINED_IMPORT_ADDEND: {
|
||||||
int ival = reader.readNextInt();
|
int ival = reader.readNextInt();
|
||||||
lib_ordinal = ival & 0xff;
|
int ordinal = ival & 0xff;
|
||||||
|
lib_ordinal = ordinal > 0xf0 ? (byte) ordinal : ordinal;
|
||||||
weak_import = ((ival >> 8) & 1) == 1;
|
weak_import = ((ival >> 8) & 1) == 1;
|
||||||
name_offset = (ival >> 9 & 0x7fffff);
|
name_offset = (ival >> 9 & 0x7fffff);
|
||||||
addend = reader.readNextInt();
|
addend = reader.readNextInt();
|
||||||
|
@ -62,7 +64,8 @@ public class DyldChainedImport implements StructConverter {
|
||||||
}
|
}
|
||||||
case DYLD_CHAINED_IMPORT_ADDEND64: {
|
case DYLD_CHAINED_IMPORT_ADDEND64: {
|
||||||
long ival = reader.readNextLong();
|
long ival = reader.readNextLong();
|
||||||
lib_ordinal = (int) (ival & 0xffff);
|
int ordinal = (int) (ival & 0xffff);
|
||||||
|
lib_ordinal = ordinal > 0xfff0 ? (short) ordinal : ordinal;
|
||||||
weak_import = ((ival >> 16) & 1) == 1;
|
weak_import = ((ival >> 16) & 1) == 1;
|
||||||
name_offset = ((ival >> 32) & 0xffffffffL);
|
name_offset = ((ival >> 32) & 0xffffffffL);
|
||||||
addend = reader.readNextLong();
|
addend = reader.readNextLong();
|
||||||
|
|
|
@ -207,7 +207,7 @@ public class DyldCacheSlideInfo4 extends DyldCacheSlideInfoCommon {
|
||||||
chainValue += valueAdd /* + slide */;
|
chainValue += valueAdd /* + slide */;
|
||||||
}
|
}
|
||||||
|
|
||||||
fixups.add(new DyldFixup(dataOffset, chainValue, 4, null, null));
|
fixups.add(new DyldFixup(dataOffset, Long.valueOf(chainValue), 4, null, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
return fixups;
|
return fixups;
|
||||||
|
|
|
@ -173,7 +173,7 @@ public abstract class DyldCacheSlideInfoCommon implements StructConverter {
|
||||||
memory.setLong(addr, fixup.value());
|
memory.setLong(addr, fixup.value());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
memory.setInt(addr, (int) fixup.value());
|
memory.setInt(addr, fixup.value().intValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,9 +19,9 @@ package ghidra.app.util.bin.format.macho.dyld;
|
||||||
* Stores information needed to perform a dyld pointer fixup
|
* Stores information needed to perform a dyld pointer fixup
|
||||||
*
|
*
|
||||||
* @param offset The offset of where to perform the fixup (from some base address/index)
|
* @param offset The offset of where to perform the fixup (from some base address/index)
|
||||||
* @param value The fixed up value
|
* @param value The fixed up value, or {@code null} if this fixup is unsupported
|
||||||
* @param size The size of the fixup in bytes
|
* @param size The size of the fixup in bytes
|
||||||
* @param symbol The symbol associated with the fixup (could be null)
|
* @param symbol The symbol associated with the fixup (could be null)
|
||||||
* @param libOrdinal The library ordinal associated with the fixup (could be null)
|
* @param libOrdinal The library ordinal associated with the fixup (could be null)
|
||||||
*/
|
*/
|
||||||
public record DyldFixup(long offset, long value, int size, String symbol, Integer libOrdinal) {}
|
public record DyldFixup(long offset, Long value, int size, String symbol, Integer libOrdinal) {}
|
||||||
|
|
|
@ -684,17 +684,14 @@ public class MachoProgramBuilder {
|
||||||
monitor.increment();
|
monitor.increment();
|
||||||
int symbolIndex = indirectSymbols.get(i);
|
int symbolIndex = indirectSymbols.get(i);
|
||||||
NList symbol = symbolTableCommand.getSymbolAt(symbolIndex);
|
NList symbol = symbolTableCommand.getSymbolAt(symbolIndex);
|
||||||
if (symbol != null) {
|
String name =
|
||||||
String name = SymbolUtilities.replaceInvalidChars(symbol.getString(), true);
|
symbol != null ? SymbolUtilities.replaceInvalidChars(symbol.getString(), true)
|
||||||
if (name != null && name.length() > 0) {
|
: "STUB_" + startAddr;
|
||||||
Function stubFunc = createOneByteFunction(name, startAddr);
|
Function stubFunc = createOneByteFunction(name, startAddr);
|
||||||
if (stubFunc != null) {
|
if (stubFunc != null && symbol != null) {
|
||||||
ExternalLocation loc = program.getExternalManager()
|
ExternalLocation loc = program.getExternalManager()
|
||||||
.addExtLocation(Library.UNKNOWN, name, null,
|
.addExtLocation(Library.UNKNOWN, name, null, SourceType.IMPORTED);
|
||||||
SourceType.IMPORTED);
|
stubFunc.setThunkedFunction(loc.createFunction());
|
||||||
stubFunc.setThunkedFunction(loc.createFunction());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
startAddr = startAddr.add(symbolSize);
|
startAddr = startAddr.add(symbolSize);
|
||||||
|
@ -1283,7 +1280,8 @@ public class MachoProgramBuilder {
|
||||||
|
|
||||||
String libraryPath = null;
|
String libraryPath = null;
|
||||||
|
|
||||||
if (command instanceof DynamicLibraryCommand dylibCommand) {
|
if (command instanceof DynamicLibraryCommand dylibCommand &&
|
||||||
|
dylibCommand.getCommandType() != LoadCommandTypes.LC_ID_DYLIB) {
|
||||||
DynamicLibrary dylib = dylibCommand.getDynamicLibrary();
|
DynamicLibrary dylib = dylibCommand.getDynamicLibrary();
|
||||||
libraryPath = dylib.getName().getString();
|
libraryPath = dylib.getName().getString();
|
||||||
}
|
}
|
||||||
|
@ -1861,6 +1859,15 @@ public class MachoProgramBuilder {
|
||||||
*/
|
*/
|
||||||
public static void fixupExternalLibrary(Program program, List<String> libraryPaths,
|
public static void fixupExternalLibrary(Program program, List<String> libraryPaths,
|
||||||
int libraryOrdinal, String symbol) throws Exception {
|
int libraryOrdinal, String symbol) throws Exception {
|
||||||
|
|
||||||
|
switch (libraryOrdinal) {
|
||||||
|
case DyldInfoCommandConstants.BIND_SPECIAL_DYLIB_SELF:
|
||||||
|
case DyldInfoCommandConstants.BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE:
|
||||||
|
case DyldInfoCommandConstants.BIND_SPECIAL_DYLIB_FLAT_LOOKUP:
|
||||||
|
case DyldInfoCommandConstants.BIND_SPECIAL_DYLIB_WEAK_LOOKUP:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ExternalManager extManager = program.getExternalManager();
|
ExternalManager extManager = program.getExternalManager();
|
||||||
int libraryIndex = libraryOrdinal - 1;
|
int libraryIndex = libraryOrdinal - 1;
|
||||||
if (libraryIndex < 0 || libraryIndex >= libraryPaths.size()) {
|
if (libraryIndex < 0 || libraryIndex >= libraryPaths.size()) {
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -52,6 +52,46 @@ public class ExternalSymbolResolver implements Closeable {
|
||||||
StringUtilities.pad("" + libraryIndex, ' ', 4));
|
StringUtilities.pad("" + libraryIndex, ' ', 4));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an ordered list of library names, as specified by the logic/rules of the original
|
||||||
|
* operating system's loader (eg. Elf / MachO dynamic library loading / symbol resolving
|
||||||
|
* rules)
|
||||||
|
*
|
||||||
|
* @param program The {@link Program}
|
||||||
|
* @return list of library names, in original order
|
||||||
|
*/
|
||||||
|
public static List<String> getOrderedRequiredLibraryNames(Program program) {
|
||||||
|
TreeMap<Integer, String> orderLibraryMap = new TreeMap<>();
|
||||||
|
Options options = program.getOptions(Program.PROGRAM_INFO);
|
||||||
|
for (String optionName : options.getOptionNames()) {
|
||||||
|
|
||||||
|
// Legacy programs may have the old "ELF Required Library [" program property, so
|
||||||
|
// we should not assume that the option name starts exactly with
|
||||||
|
// REQUIRED_LIBRARY_PROPERTY_PREFIX. We must deal with a potential substring at the
|
||||||
|
// start of the option name.
|
||||||
|
int prefixIndex = optionName.indexOf(REQUIRED_LIBRARY_PROPERTY_PREFIX);
|
||||||
|
if (prefixIndex == -1 || !optionName.endsWith("]")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String libName = options.getString(optionName, null);
|
||||||
|
if (libName == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String indexStr = optionName
|
||||||
|
.substring(prefixIndex + REQUIRED_LIBRARY_PROPERTY_PREFIX.length(),
|
||||||
|
optionName.length() - 1)
|
||||||
|
.trim();
|
||||||
|
try {
|
||||||
|
orderLibraryMap.put(Integer.parseInt(indexStr), libName.trim());
|
||||||
|
}
|
||||||
|
catch (NumberFormatException e) {
|
||||||
|
Msg.error(ExternalSymbolResolver.class,
|
||||||
|
"Program contains invalid property: " + optionName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new ArrayList<>(orderLibraryMap.values());
|
||||||
|
}
|
||||||
|
|
||||||
private final ProjectData projectData;
|
private final ProjectData projectData;
|
||||||
private final TaskMonitor monitor;
|
private final TaskMonitor monitor;
|
||||||
private final List<ProgramSymbolResolver> programsToFix = new ArrayList<>();
|
private final List<ProgramSymbolResolver> programsToFix = new ArrayList<>();
|
||||||
|
@ -333,7 +373,7 @@ public class ExternalSymbolResolver implements Closeable {
|
||||||
private List<ExtLibInfo> getLibsToSearch() throws CancelledException {
|
private List<ExtLibInfo> getLibsToSearch() throws CancelledException {
|
||||||
List<ExtLibInfo> result = new ArrayList<>();
|
List<ExtLibInfo> result = new ArrayList<>();
|
||||||
ExternalManager externalManager = program.getExternalManager();
|
ExternalManager externalManager = program.getExternalManager();
|
||||||
for (String libName : getOrderedRequiredLibraryNames()) {
|
for (String libName : getOrderedRequiredLibraryNames(program)) {
|
||||||
Library lib = externalManager.getExternalLibrary(libName);
|
Library lib = externalManager.getExternalLibrary(libName);
|
||||||
String libPath = lib != null ? lib.getAssociatedProgramPath() : null;
|
String libPath = lib != null ? lib.getAssociatedProgramPath() : null;
|
||||||
Program libProg = libPath != null ? getLibraryProgram(libPath) : null;
|
Program libProg = libPath != null ? getLibraryProgram(libPath) : null;
|
||||||
|
@ -409,46 +449,6 @@ public class ExternalSymbolResolver implements Closeable {
|
||||||
}
|
}
|
||||||
return symbolIds;
|
return symbolIds;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an ordered list of library names, as specified by the logic/rules of the original
|
|
||||||
* operating system's loader (eg. Elf / MachO dynamic library loading / symbol resolving
|
|
||||||
* rules)
|
|
||||||
*
|
|
||||||
* @return list of library names, in original order
|
|
||||||
*/
|
|
||||||
private Collection<String> getOrderedRequiredLibraryNames() {
|
|
||||||
TreeMap<Integer, String> orderLibraryMap = new TreeMap<>();
|
|
||||||
Options options = program.getOptions(Program.PROGRAM_INFO);
|
|
||||||
for (String optionName : options.getOptionNames()) {
|
|
||||||
|
|
||||||
// Legacy programs may have the old "ELF Required Library [" program property, so
|
|
||||||
// we should not assume that the option name starts exactly with
|
|
||||||
// REQUIRED_LIBRARY_PROPERTY_PREFIX. We must deal with a potential substring at the
|
|
||||||
// start of the option name.
|
|
||||||
int prefixIndex = optionName.indexOf(REQUIRED_LIBRARY_PROPERTY_PREFIX);
|
|
||||||
if (prefixIndex == -1 || !optionName.endsWith("]")) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
String libName = options.getString(optionName, null);
|
|
||||||
if (libName == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
String indexStr = optionName
|
|
||||||
.substring(prefixIndex + REQUIRED_LIBRARY_PROPERTY_PREFIX.length(),
|
|
||||||
optionName.length() - 1)
|
|
||||||
.trim();
|
|
||||||
try {
|
|
||||||
orderLibraryMap.put(Integer.parseInt(indexStr), libName.trim());
|
|
||||||
}
|
|
||||||
catch (NumberFormatException e) {
|
|
||||||
Msg.error(ExternalSymbolResolver.class,
|
|
||||||
"Program contains invalid property: " + optionName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return orderLibraryMap.values();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -352,9 +352,9 @@ id="the-listings-are-not-in-sync-i.e.-they-do-not-move-together."
|
||||||
class="level3">
|
class="level3">
|
||||||
<h3>The listings are not in sync, i.e., they do not move together.</h3>
|
<h3>The listings are not in sync, i.e., they do not move together.</h3>
|
||||||
<p>First, check that synchronization is enabled. This is the default
|
<p>First, check that synchronization is enabled. This is the default
|
||||||
behavior, but, still, check it first. In the top-right of the Dynamic
|
behavior, but, still, check it first. In the <strong>Debugger →
|
||||||
Listing is its local drop-down menu. Click it and check that
|
Synchronization</strong> menu, check that <strong>Synchronize Static and
|
||||||
<strong>Auto-Sync Cursor with Static Listing</strong> is selected.</p>
|
Dynamic Locations</strong> is selected.</p>
|
||||||
<p>If that does not work, check the top-left label of the Dynamic
|
<p>If that does not work, check the top-left label of the Dynamic
|
||||||
Listing to see what module you are in. Also check the Debug Console
|
Listing to see what module you are in. Also check the Debug Console
|
||||||
window. If you are in a system library, e.g., <code>ld-linux</code>,
|
window. If you are in a system library, e.g., <code>ld-linux</code>,
|
||||||
|
|
|
@ -167,8 +167,7 @@ The re-use of connections and/or the use of multiple concurrent connections is *
|
||||||
|
|
||||||
First, check that synchronization is enabled.
|
First, check that synchronization is enabled.
|
||||||
This is the default behavior, but, still, check it first.
|
This is the default behavior, but, still, check it first.
|
||||||
In the top-right of the Dynamic Listing is its local drop-down menu.
|
In the **Debugger → Synchronization** menu, check that **Synchronize Static and Dynamic Locations** is selected.
|
||||||
Click it and check that **Auto-Sync Cursor with Static Listing** is selected.
|
|
||||||
|
|
||||||
If that does not work, check the top-left label of the Dynamic Listing to see what module you are in.
|
If that does not work, check the top-left label of the Dynamic Listing to see what module you are in.
|
||||||
Also check the Debug Console window.
|
Also check the Debug Console window.
|
||||||
|
|
|
@ -162,8 +162,7 @@ src="images/breakpoint-enable.png" alt="set breakpoint" /> Set
|
||||||
Breakpoint, press <strong><code>K</code></strong> on the keyboard, or
|
Breakpoint, press <strong><code>K</code></strong> on the keyboard, or
|
||||||
double-click the margin.</li>
|
double-click the margin.</li>
|
||||||
<li>From the Breakpoints window, use the <strong>Set Breakpoint</strong>
|
<li>From the Breakpoints window, use the <strong>Set Breakpoint</strong>
|
||||||
dropdown to access the various breakpoint actions defined by
|
dropdown to access the various breakpoint actions defined by GDB.</li>
|
||||||
GDB.</li>
|
|
||||||
<li>From the Terminal window, use the GDB command, e.g.,
|
<li>From the Terminal window, use the GDB command, e.g.,
|
||||||
<code>break main</code>.</li>
|
<code>break main</code>.</li>
|
||||||
</ol>
|
</ol>
|
||||||
|
|
|
@ -239,11 +239,11 @@ caused the target to break. This only applies to snapshots that were
|
||||||
created because of an event, which is most.</li>
|
created because of an event, which is most.</li>
|
||||||
<li>The <strong>PC</strong> column gives the address of the next
|
<li>The <strong>PC</strong> column gives the address of the next
|
||||||
instruction.</li>
|
instruction.</li>
|
||||||
|
<li>The <strong>Module</strong> column gives the name of the module
|
||||||
|
containing the PC.</li>
|
||||||
<li>The <strong>Function</strong> column gives the name of the function
|
<li>The <strong>Function</strong> column gives the name of the function
|
||||||
containing the PC mapped to its static program database, if
|
containing the PC mapped to its static program database, if
|
||||||
available.</li>
|
available.</li>
|
||||||
<li>The <strong>Module</strong> column gives the name of the module
|
|
||||||
containing the PC.</li>
|
|
||||||
<li>The <strong>Description</strong> column describes the event that
|
<li>The <strong>Description</strong> column describes the event that
|
||||||
generated the snapshot. This can be edited in the table, or by pressing
|
generated the snapshot. This can be edited in the table, or by pressing
|
||||||
<strong><code>CTRL</code>-<code>SHIFT</code>-<code>N</code></strong> to
|
<strong><code>CTRL</code>-<code>SHIFT</code>-<code>N</code></strong> to
|
||||||
|
|
|
@ -128,8 +128,8 @@ The columns are:
|
||||||
* The **Event Thread** column indicates which thread caused the target to break.
|
* The **Event Thread** column indicates which thread caused the target to break.
|
||||||
This only applies to snapshots that were created because of an event, which is most.
|
This only applies to snapshots that were created because of an event, which is most.
|
||||||
* The **PC** column gives the address of the next instruction.
|
* The **PC** column gives the address of the next instruction.
|
||||||
* The **Function** column gives the name of the function containing the PC mapped to its static program database, if available.
|
|
||||||
* The **Module** column gives the name of the module containing the PC.
|
* The **Module** column gives the name of the module containing the PC.
|
||||||
|
* The **Function** column gives the name of the function containing the PC mapped to its static program database, if available.
|
||||||
* The **Description** column describes the event that generated the snapshot.
|
* The **Description** column describes the event that generated the snapshot.
|
||||||
This can be edited in the table, or by pressing **`CTRL`-`SHIFT`-`N`** to mark interesting snapshots.
|
This can be edited in the table, or by pressing **`CTRL`-`SHIFT`-`N`** to mark interesting snapshots.
|
||||||
|
|
||||||
|
|
|
@ -55,9 +55,9 @@ Mappings</a></li>
|
||||||
<li><a href="#moving-knowledge-from-dynamic-to-static"
|
<li><a href="#moving-knowledge-from-dynamic-to-static"
|
||||||
id="toc-moving-knowledge-from-dynamic-to-static">Moving Knowledge from
|
id="toc-moving-knowledge-from-dynamic-to-static">Moving Knowledge from
|
||||||
Dynamic to Static</a></li>
|
Dynamic to Static</a></li>
|
||||||
<li><a href="#exercise-export-and-map-ncurses"
|
<li><a href="#exercise-export-and-map-system-supplied-dso"
|
||||||
id="toc-exercise-export-and-map-ncurses">Exercise: Export and Map
|
id="toc-exercise-export-and-map-system-supplied-dso">Exercise: Export
|
||||||
<code>ncurses</code></a></li>
|
and Map <code>system-supplied DSO</code></a></li>
|
||||||
<li><a href="#exercise-cheat-like-the-devs"
|
<li><a href="#exercise-cheat-like-the-devs"
|
||||||
id="toc-exercise-cheat-like-the-devs">Exercise: Cheat Like the
|
id="toc-exercise-cheat-like-the-devs">Exercise: Cheat Like the
|
||||||
Devs</a></li>
|
Devs</a></li>
|
||||||
|
@ -276,7 +276,7 @@ anyway.</p></li>
|
||||||
<li><p>The table displays the <em>copy plan</em>. For a new program,
|
<li><p>The table displays the <em>copy plan</em>. For a new program,
|
||||||
this will copy with an identical mapping of addresses, which is probably
|
this will copy with an identical mapping of addresses, which is probably
|
||||||
the best plan, since the target system has already applied fixups. Do
|
the best plan, since the target system has already applied fixups. Do
|
||||||
not change any addresses, lest your corrupt references in the
|
not change any addresses, lest you corrupt references in the
|
||||||
copy.</p></li>
|
copy.</p></li>
|
||||||
<li><p>Click <strong>Copy</strong>.</p></li>
|
<li><p>Click <strong>Copy</strong>.</p></li>
|
||||||
<li><p>When prompted, name the program <code>libncurses</code>.</p></li>
|
<li><p>When prompted, name the program <code>libncurses</code>.</p></li>
|
||||||
|
@ -296,8 +296,9 @@ libncurses</strong>.</li>
|
||||||
<li>Check the proposed mapping and click <strong>OK</strong>.</li>
|
<li>Check the proposed mapping and click <strong>OK</strong>.</li>
|
||||||
</ol>
|
</ol>
|
||||||
</section>
|
</section>
|
||||||
<section id="exercise-export-and-map-ncurses" class="level2">
|
<section id="exercise-export-and-map-system-supplied-dso"
|
||||||
<h2>Exercise: Export and Map <code>ncurses</code></h2>
|
class="level2">
|
||||||
|
<h2>Exercise: Export and Map <code>system-supplied DSO</code></h2>
|
||||||
<p>Repeat this technique for the “system-supplied DSO” module. In
|
<p>Repeat this technique for the “system-supplied DSO” module. In
|
||||||
practice, there is no real reason to do this, but this particular module
|
practice, there is no real reason to do this, but this particular module
|
||||||
prevents you from using <strong>Import From File System</strong>.</p>
|
prevents you from using <strong>Import From File System</strong>.</p>
|
||||||
|
|
|
@ -144,7 +144,7 @@ For demonstration, we will walk through this second case, pretending we cannot l
|
||||||
1. It is probably best to include everything, though **Bytes** is the bare minimum.
|
1. It is probably best to include everything, though **Bytes** is the bare minimum.
|
||||||
1. The table displays the *copy plan*.
|
1. The table displays the *copy plan*.
|
||||||
For a new program, this will copy with an identical mapping of addresses, which is probably the best plan, since the target system has already applied fixups.
|
For a new program, this will copy with an identical mapping of addresses, which is probably the best plan, since the target system has already applied fixups.
|
||||||
Do not change any addresses, lest your corrupt references in the copy.
|
Do not change any addresses, lest you corrupt references in the copy.
|
||||||
1. Click **Copy**.
|
1. Click **Copy**.
|
||||||
1. When prompted, name the program `libncurses`.
|
1. When prompted, name the program `libncurses`.
|
||||||
1. You may need to click the `termmines` tab in the Static Listing to get the UI to completely update.
|
1. You may need to click the `termmines` tab in the Static Listing to get the UI to completely update.
|
||||||
|
@ -157,7 +157,7 @@ Undoubtedly, we would like to map that new program into our dynamic session.
|
||||||
1. In the top pane of the Modules window, right-click `libncurses` and choose **Map to libncurses**.
|
1. In the top pane of the Modules window, right-click `libncurses` and choose **Map to libncurses**.
|
||||||
1. Check the proposed mapping and click **OK**.
|
1. Check the proposed mapping and click **OK**.
|
||||||
|
|
||||||
## Exercise: Export and Map `ncurses`
|
## Exercise: Export and Map `system-supplied DSO`
|
||||||
|
|
||||||
Repeat this technique for the "system-supplied DSO" module.
|
Repeat this technique for the "system-supplied DSO" module.
|
||||||
In practice, there is no real reason to do this, but this particular module prevents you from using **Import From File System**.
|
In practice, there is no real reason to do this, but this particular module prevents you from using **Import From File System**.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue