mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 09:49:23 +02:00
Merge branch 'GP-5429_ryanmkurtz_reexport-obj-fix'
This commit is contained in:
commit
cdd68cc791
6 changed files with 63 additions and 46 deletions
|
@ -159,7 +159,7 @@ public abstract class AbstractLibrarySupportLoader extends AbstractProgramLoader
|
|||
*/
|
||||
@Override
|
||||
protected void postLoadProgramFixups(List<Loaded<Program>> loadedPrograms, Project project,
|
||||
LoadSpec loadSpec, List<Option> options, MessageLog messageLog, TaskMonitor monitor)
|
||||
LoadSpec loadSpec, List<Option> options, MessageLog log, TaskMonitor monitor)
|
||||
throws CancelledException, IOException {
|
||||
if (loadedPrograms.isEmpty() ||
|
||||
(!isLinkExistingLibraries(options) && !isLoadLibraries(options))) {
|
||||
|
@ -167,10 +167,10 @@ public abstract class AbstractLibrarySupportLoader extends AbstractProgramLoader
|
|||
}
|
||||
|
||||
List<DomainFolder> searchFolders =
|
||||
getLibrarySearchFolders(loadedPrograms, project, options);
|
||||
getLibrarySearchFolders(loadedPrograms, project, options, log);
|
||||
|
||||
List<LibrarySearchPath> searchPaths = getLibrarySearchPaths(
|
||||
loadedPrograms.getFirst().getDomainObject(), loadSpec, options, messageLog, monitor);
|
||||
loadedPrograms.getFirst().getDomainObject(), loadSpec, options, log, monitor);
|
||||
|
||||
List<Loaded<Program>> saveablePrograms =
|
||||
loadedPrograms.stream().filter(Predicate.not(Loaded::shouldDiscard)).toList();
|
||||
|
@ -191,7 +191,7 @@ public abstract class AbstractLibrarySupportLoader extends AbstractProgramLoader
|
|||
int id = program.startTransaction("Resolving external references");
|
||||
try {
|
||||
resolveExternalLibraries(program, saveablePrograms, searchFolders, searchPaths,
|
||||
options, monitor, messageLog);
|
||||
options, monitor, log);
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(id, true);
|
||||
|
@ -286,12 +286,13 @@ public abstract class AbstractLibrarySupportLoader extends AbstractProgramLoader
|
|||
* @param projectFolderPath The project folder path the program will get saved to. Could be null
|
||||
* if the program is not getting saved to the project.
|
||||
* @param options a {@link List} of {@link Option}s
|
||||
* @param log The log
|
||||
* @return The path of the project folder to search for existing libraries, or null if no
|
||||
* project folders can be or should be searched
|
||||
*/
|
||||
protected DomainFolder getLinkSearchFolder(Project project, Program program,
|
||||
String projectFolderPath, List<Option> options) {
|
||||
if (!shouldSearchAllPaths(program, options) && !isLinkExistingLibraries(options)) {
|
||||
String projectFolderPath, List<Option> options, MessageLog log) {
|
||||
if (!shouldSearchAllPaths(program, options, log) && !isLinkExistingLibraries(options)) {
|
||||
return null;
|
||||
}
|
||||
if (project == null) {
|
||||
|
@ -401,18 +402,19 @@ public abstract class AbstractLibrarySupportLoader extends AbstractProgramLoader
|
|||
* @param loadedPrograms the list of {@link Loaded} {@link Program}s
|
||||
* @param project The {@link Project} to load into. Could be null if there is no project.
|
||||
* @param options The {@link List} of {@link Option}s
|
||||
* @param log The log
|
||||
* @return A {@link List} of library search {@link DomainFolder folders} based on the current
|
||||
* options
|
||||
*/
|
||||
protected List<DomainFolder> getLibrarySearchFolders(List<Loaded<Program>> loadedPrograms,
|
||||
Project project, List<Option> options) {
|
||||
Project project, List<Option> options, MessageLog log) {
|
||||
List<DomainFolder> searchFolders = new ArrayList<>();
|
||||
String projectFolderPath = loadedPrograms.get(0).getProjectFolderPath();
|
||||
String destPath = getLibraryDestinationFolderPath(project, projectFolderPath, options);
|
||||
DomainFolder destSearchFolder =
|
||||
getLibraryDestinationSearchFolder(project, destPath, options);
|
||||
DomainFolder linkSearchFolder = getLinkSearchFolder(project,
|
||||
loadedPrograms.getFirst().getDomainObject(), projectFolderPath, options);
|
||||
loadedPrograms.getFirst().getDomainObject(), projectFolderPath, options, log);
|
||||
Optional.ofNullable(destSearchFolder).ifPresent(searchFolders::add);
|
||||
Optional.ofNullable(linkSearchFolder).ifPresent(searchFolders::add);
|
||||
return searchFolders;
|
||||
|
@ -424,9 +426,10 @@ public abstract class AbstractLibrarySupportLoader extends AbstractProgramLoader
|
|||
*
|
||||
* @param program The {@link Program} being loaded
|
||||
* @param options a {@link List} of {@link Option}s
|
||||
* @param log The log
|
||||
* @return True if all possible search paths should be used, regardless of what options are set
|
||||
*/
|
||||
protected boolean shouldSearchAllPaths(Program program, List<Option> options) {
|
||||
protected boolean shouldSearchAllPaths(Program program, List<Option> options, MessageLog log) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -527,7 +530,7 @@ public abstract class AbstractLibrarySupportLoader extends AbstractProgramLoader
|
|||
List<LibrarySearchPath> searchPaths =
|
||||
getLibrarySearchPaths(program, desiredLoadSpec, options, log, monitor);
|
||||
DomainFolder linkSearchFolder =
|
||||
getLinkSearchFolder(project, program, projectFolderPath, options);
|
||||
getLinkSearchFolder(project, program, projectFolderPath, options, log);
|
||||
String libraryDestFolderPath =
|
||||
getLibraryDestinationFolderPath(project, projectFolderPath, options);
|
||||
DomainFolder libraryDestFolder =
|
||||
|
@ -554,7 +557,7 @@ public abstract class AbstractLibrarySupportLoader extends AbstractProgramLoader
|
|||
log.appendMsg("Found %s in %s...".formatted(library, linkSearchFolder));
|
||||
log.appendMsg("------------------------------------------------\n");
|
||||
}
|
||||
else if (isLoadLibraries(options) || shouldSearchAllPaths(program, options)) {
|
||||
else if (isLoadLibraries(options) || shouldSearchAllPaths(program, options, log)) {
|
||||
Loaded<Program> loadedLibrary = loadLibraryFromSearchPaths(library, provider,
|
||||
customSearchPaths, libraryDestFolderPath, unprocessed, depth,
|
||||
desiredLoadSpec, options, log, consumer, monitor);
|
||||
|
@ -894,12 +897,11 @@ public abstract class AbstractLibrarySupportLoader extends AbstractProgramLoader
|
|||
|
||||
private void resolveExternalLibraries(Program program, List<Loaded<Program>> loadedPrograms,
|
||||
List<DomainFolder> searchFolders, List<LibrarySearchPath> fsSearchPaths,
|
||||
List<Option> options, TaskMonitor monitor, MessageLog messageLog)
|
||||
List<Option> options, TaskMonitor monitor, MessageLog log)
|
||||
throws CancelledException {
|
||||
ExternalManager extManager = program.getExternalManager();
|
||||
String[] extLibNames = extManager.getExternalLibraryNames();
|
||||
messageLog.appendMsg(
|
||||
"Linking the External Programs of '%s' to imported libraries..."
|
||||
log.appendMsg("Linking the External Programs of '%s' to imported libraries..."
|
||||
.formatted(program.getName()));
|
||||
for (String externalLibName : extLibNames) {
|
||||
if (Library.UNKNOWN.equals(externalLibName)) {
|
||||
|
@ -911,7 +913,7 @@ public abstract class AbstractLibrarySupportLoader extends AbstractProgramLoader
|
|||
if (match != null) {
|
||||
String path = match.getProjectFolderPath() + match.getName();
|
||||
extManager.setExternalPath(externalLibName, path, false);
|
||||
messageLog.appendMsg(" [" + externalLibName + "] -> [" + path + "]");
|
||||
log.appendMsg(" [" + externalLibName + "] -> [" + path + "]");
|
||||
}
|
||||
else {
|
||||
boolean found = false;
|
||||
|
@ -921,14 +923,14 @@ public abstract class AbstractLibrarySupportLoader extends AbstractProgramLoader
|
|||
if (alreadyImportedLib != null) {
|
||||
extManager.setExternalPath(externalLibName,
|
||||
alreadyImportedLib.getPathname(), false);
|
||||
messageLog.appendMsg(" [" + externalLibName + "] -> [" +
|
||||
log.appendMsg(" [" + externalLibName + "] -> [" +
|
||||
alreadyImportedLib.getPathname() + "] (previously imported)");
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
messageLog.appendMsg(" [" + externalLibName + "] -> not found in project");
|
||||
log.appendMsg(" [" + externalLibName + "] -> not found in project");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -936,7 +938,7 @@ public abstract class AbstractLibrarySupportLoader extends AbstractProgramLoader
|
|||
Msg.error(this, "Bad library name: " + externalLibName, e);
|
||||
}
|
||||
}
|
||||
messageLog.appendMsg("------------------------------------------------\n");
|
||||
log.appendMsg("------------------------------------------------\n");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1023,7 +1025,7 @@ public abstract class AbstractLibrarySupportLoader extends AbstractProgramLoader
|
|||
*/
|
||||
protected List<LibrarySearchPath> getLibrarySearchPaths(Program program, LoadSpec loadSpec,
|
||||
List<Option> options, MessageLog log, TaskMonitor monitor) throws CancelledException {
|
||||
if (!isLoadLibraries(options) && !shouldSearchAllPaths(program, options)) {
|
||||
if (!isLoadLibraries(options) && !shouldSearchAllPaths(program, options, log)) {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
|
|
|
@ -71,7 +71,7 @@ public abstract class AbstractOrdinalSupportLoader extends AbstractLibrarySuppor
|
|||
}
|
||||
|
||||
@Override
|
||||
protected boolean shouldSearchAllPaths(Program program, List<Option> options) {
|
||||
protected boolean shouldSearchAllPaths(Program program, List<Option> options, MessageLog log) {
|
||||
return shouldPerformOrdinalLookup(options);
|
||||
}
|
||||
|
||||
|
|
|
@ -41,7 +41,6 @@ import ghidra.program.model.listing.Function;
|
|||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.util.LittleEndianDataConverter;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
import util.CollectionUtils;
|
||||
|
@ -310,20 +309,25 @@ public class MachoLoader extends AbstractLibrarySupportLoader {
|
|||
* set and the Mach-O actually has {@code LC_REEXPORT_DYLIB} entries.
|
||||
*/
|
||||
@Override
|
||||
protected boolean shouldSearchAllPaths(Program program, List<Option> options) {
|
||||
if (super.shouldSearchAllPaths(program, options)) {
|
||||
protected boolean shouldSearchAllPaths(Program program, List<Option> options, MessageLog log) {
|
||||
if (super.shouldSearchAllPaths(program, options, log)) {
|
||||
return true;
|
||||
}
|
||||
if (shouldPerformReexports(options)) {
|
||||
try {
|
||||
ByteProvider provider = new MemoryByteProvider(program.getMemory(),
|
||||
program.getImageBase());
|
||||
if (new MachHeader(provider).parseAndCheck(LoadCommandTypes.LC_REEXPORT_DYLIB)) {
|
||||
Symbol header =
|
||||
program.getSymbolTable().getSymbols(MachoProgramBuilder.HEADER_SYMBOL).next();
|
||||
if (header == null) {
|
||||
return false;
|
||||
}
|
||||
ByteProvider p = new MemoryByteProvider(program.getMemory(), header.getAddress());
|
||||
if (new MachHeader(p).parseAndCheck(LoadCommandTypes.LC_REEXPORT_DYLIB)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (IOException | MachException e) {
|
||||
Msg.error(this, "Failed to parse Mach-O header for: " + program.getName());
|
||||
catch (Exception e) {
|
||||
log.appendMsg("Failed to parse Mach-O header for: '%s': %s"
|
||||
.formatted(program.getName(), e.getMessage()));
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
@ -348,7 +352,7 @@ public class MachoLoader extends AbstractLibrarySupportLoader {
|
|||
}
|
||||
|
||||
try {
|
||||
for (String path : getReexportPaths(lib)) {
|
||||
for (String path : getReexportPaths(lib, log)) {
|
||||
unprocessed.add(new UnprocessedLibrary(path, depth, depth == 1));
|
||||
}
|
||||
}
|
||||
|
@ -361,12 +365,21 @@ public class MachoLoader extends AbstractLibrarySupportLoader {
|
|||
* Gets a {@link List} of reexport library paths from the given {@link Program}
|
||||
*
|
||||
* @param program The {@link Program}
|
||||
* @param log The log
|
||||
* @return A {@link List} of reexport library paths from the given {@link Program}
|
||||
* @throws MachException if there was a problem parsing the Mach-O {@link Program}
|
||||
* @throws IOException if there was an IO-related error
|
||||
*/
|
||||
private List<String> getReexportPaths(Program program) throws MachException, IOException {
|
||||
ByteProvider p = new MemoryByteProvider(program.getMemory(), program.getImageBase());
|
||||
private List<String> getReexportPaths(Program program, MessageLog log)
|
||||
throws MachException, IOException {
|
||||
Symbol header =
|
||||
program.getSymbolTable().getSymbols(MachoProgramBuilder.HEADER_SYMBOL).next();
|
||||
if (header == null) {
|
||||
log.appendMsg("Failed to lookup reexport paths...couldn't find '%s' symbol"
|
||||
.formatted(MachoProgramBuilder.HEADER_SYMBOL));
|
||||
return List.of();
|
||||
}
|
||||
ByteProvider p = new MemoryByteProvider(program.getMemory(), header.getAddress());
|
||||
return new MachHeader(p).parseReexports()
|
||||
.stream()
|
||||
.map(DynamicLibraryCommand::getDynamicLibrary)
|
||||
|
@ -382,17 +395,16 @@ public class MachoLoader extends AbstractLibrarySupportLoader {
|
|||
*/
|
||||
@Override
|
||||
protected void postLoadProgramFixups(List<Loaded<Program>> loadedPrograms, Project project,
|
||||
LoadSpec loadSpec, List<Option> options, MessageLog messageLog, TaskMonitor monitor)
|
||||
LoadSpec loadSpec, List<Option> options, MessageLog log, TaskMonitor monitor)
|
||||
throws CancelledException, IOException {
|
||||
|
||||
if (shouldPerformReexports(options)) {
|
||||
|
||||
List<DomainFolder> searchFolders =
|
||||
getLibrarySearchFolders(loadedPrograms, project, options);
|
||||
getLibrarySearchFolders(loadedPrograms, project, options, log);
|
||||
|
||||
List<LibrarySearchPath> searchPaths =
|
||||
getLibrarySearchPaths(loadedPrograms.getFirst().getDomainObject(), loadSpec,
|
||||
options, messageLog, monitor);
|
||||
List<LibrarySearchPath> searchPaths = getLibrarySearchPaths(
|
||||
loadedPrograms.getFirst().getDomainObject(), loadSpec, options, log, monitor);
|
||||
|
||||
monitor.initialize(loadedPrograms.size());
|
||||
for (Loaded<Program> loadedProgram : loadedPrograms) {
|
||||
|
@ -402,10 +414,10 @@ public class MachoLoader extends AbstractLibrarySupportLoader {
|
|||
int id = program.startTransaction("Reexporting");
|
||||
try {
|
||||
reexport(program, loadedPrograms, searchFolders, searchPaths, options, monitor,
|
||||
messageLog);
|
||||
log);
|
||||
}
|
||||
catch (Exception e) {
|
||||
messageLog.appendException(e);
|
||||
log.appendException(e);
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(id, true);
|
||||
|
@ -413,7 +425,7 @@ public class MachoLoader extends AbstractLibrarySupportLoader {
|
|||
}
|
||||
}
|
||||
|
||||
super.postLoadProgramFixups(loadedPrograms, project, loadSpec, options, messageLog,
|
||||
super.postLoadProgramFixups(loadedPrograms, project, loadSpec, options, log,
|
||||
monitor);
|
||||
}
|
||||
|
||||
|
@ -428,16 +440,16 @@ public class MachoLoader extends AbstractLibrarySupportLoader {
|
|||
* @param searchPaths A {@link List} of file system search paths that will be searched
|
||||
* @param options The load options
|
||||
* @param monitor A cancelable task monitor
|
||||
* @param messageLog The log
|
||||
* @param log The log
|
||||
* @throws CancelledException if the user cancelled the load operation
|
||||
* @throws IOException if there was an IO-related error during the load
|
||||
*/
|
||||
private void reexport(Program program, List<Loaded<Program>> loadedPrograms,
|
||||
List<DomainFolder> searchFolders, List<LibrarySearchPath> searchPaths,
|
||||
List<Option> options, TaskMonitor monitor, MessageLog messageLog)
|
||||
List<Option> options, TaskMonitor monitor, MessageLog log)
|
||||
throws CancelledException, Exception {
|
||||
|
||||
for (String path : getReexportPaths(program)) {
|
||||
for (String path : getReexportPaths(program, log)) {
|
||||
monitor.checkCancelled();
|
||||
Program programToRelease = null;
|
||||
try {
|
||||
|
@ -469,7 +481,7 @@ public class MachoLoader extends AbstractLibrarySupportLoader {
|
|||
.filter(Objects::nonNull)
|
||||
.toList();
|
||||
Address addr = MachoProgramUtils.addExternalBlock(program,
|
||||
reexportedSymbols.size() * 8, messageLog);
|
||||
reexportedSymbols.size() * 8, log);
|
||||
monitor.initialize(reexportedSymbols.size(), "Reexporting symbols...");
|
||||
for (Symbol symbol : reexportedSymbols) {
|
||||
monitor.increment();
|
||||
|
|
|
@ -66,6 +66,8 @@ import ghidra.util.task.TaskMonitor;
|
|||
*/
|
||||
public class MachoProgramBuilder {
|
||||
|
||||
public static final String HEADER_SYMBOL = "MACH_HEADER";
|
||||
|
||||
protected MachHeader machoHeader;
|
||||
protected Program program;
|
||||
protected ByteProvider provider;
|
||||
|
@ -975,6 +977,7 @@ public class MachoProgramBuilder {
|
|||
try {
|
||||
DataUtilities.createData(program, headerAddr, header.toDataType(), -1,
|
||||
DataUtilities.ClearDataMode.CHECK_FOR_SPACE);
|
||||
program.getSymbolTable().createLabel(headerAddr, HEADER_SYMBOL, SourceType.IMPORTED);
|
||||
|
||||
monitor.initialize(header.getLoadCommands().size(), "Marking up header...");
|
||||
for (LoadCommand loadCommand : header.getLoadCommands()) {
|
||||
|
|
|
@ -169,7 +169,7 @@ public class DyldCacheExtractLoader extends MachoLoader {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected boolean shouldSearchAllPaths(Program program, List<Option> options) {
|
||||
protected boolean shouldSearchAllPaths(Program program, List<Option> options, MessageLog log) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -102,7 +102,7 @@ public class MachoFileSetExtractLoader extends MachoLoader {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected boolean shouldSearchAllPaths(Program program, List<Option> options) {
|
||||
protected boolean shouldSearchAllPaths(Program program, List<Option> options, MessageLog log) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue