From dcc3043840ee130a97a1f41dc8bfa31368150c50 Mon Sep 17 00:00:00 2001 From: dev747368 <48332326+dev747368@users.noreply.github.com> Date: Wed, 7 Feb 2024 14:10:19 -0500 Subject: [PATCH] GP-4145 improve External Symbol Resolver analyzer handling of binaries The analyzer wasn't handling external library binaries that needed to be updated because the Ghidra version changed, and wasn't logging any error messages or other useful diagnostic info. --- .../ExternalSymbolResolverAnalyzer.java | 78 +-- .../ghidra/app/util/opinion/ElfLoader.java | 12 +- .../program/util/ExternalSymbolResolver.java | 572 +++++++++++++----- 3 files changed, 427 insertions(+), 235 deletions(-) diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/ExternalSymbolResolverAnalyzer.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/ExternalSymbolResolverAnalyzer.java index 4533c86caa..a7f07deaa3 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/ExternalSymbolResolverAnalyzer.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/ExternalSymbolResolverAnalyzer.java @@ -15,21 +15,16 @@ */ package ghidra.app.plugin.core.analysis; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - import ghidra.app.services.*; import ghidra.app.util.importer.MessageLog; -import ghidra.app.util.opinion.*; -import ghidra.framework.model.*; +import ghidra.app.util.opinion.ElfLoader; +import ghidra.app.util.opinion.MachoLoader; import ghidra.framework.options.Options; import ghidra.program.model.address.AddressSetView; -import ghidra.program.model.listing.Library; import ghidra.program.model.listing.Program; import ghidra.program.util.ExternalSymbolResolver; +import ghidra.util.Msg; import ghidra.util.exception.CancelledException; -import ghidra.util.exception.VersionException; import ghidra.util.task.TaskMonitor; /** @@ -61,7 +56,7 @@ public class ExternalSymbolResolverAnalyzer extends AbstractAnalyzer { if (program.getDomainFile().getParent() == null) { return false; } - + Options options = program.getOptions(Program.PROGRAM_INFO); String format = options.getString("Executable Format", null); return ElfLoader.ELF_NAME.equals(format) || MachoLoader.MACH_O_NAME.equals(format); @@ -71,65 +66,16 @@ public class ExternalSymbolResolverAnalyzer extends AbstractAnalyzer { public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log) throws CancelledException { - Object consumer = new Object(); - log = new MessageLog(); // For now, we don't want the analysis log spammed - ProjectData projectData = program.getDomainFile().getParent().getProjectData(); - List> loadedPrograms = new ArrayList<>(); - - // Add program to list - loadedPrograms.add(new Loaded<>(program, program.getName(), - program.getDomainFile().getParent().getPathname())); - - // Add external libraries to list - for (Library extLibrary : ExternalSymbolResolver.getLibrarySearchList(program)) { - monitor.checkCancelled(); - String libPath = extLibrary.getAssociatedProgramPath(); - if (libPath == null) { - continue; + try (ExternalSymbolResolver esr = new ExternalSymbolResolver( + program.getDomainFile().getParent().getProjectData(), monitor)) { + esr.addProgramToFixup(program); + esr.fixUnresolvedExternalSymbols(); + esr.logInfo(s -> Msg.info(this, s), false); + if (esr.hasProblemLibraries()) { + // causes a popup message at end of analysis session + esr.logInfo(log::appendMsg, true); } - - DomainFile libDomainFile = projectData.getFile(libPath); - if (libDomainFile == null) { - log.appendMsg("Referenced external program not found: " + libPath); - continue; - } - - try { - DomainObject libDomainObject = - libDomainFile.getDomainObject(consumer, false, false, monitor); - if (libDomainObject instanceof Program p) { - loadedPrograms.add(new Loaded<>(p, libDomainFile.getName(), - libDomainFile.getParent().getPathname())); - } - else { - libDomainObject.release(consumer); - log.appendMsg("Referenced external program is not a program: " + libPath); - } - } - catch (IOException e) { - log.appendMsg("Failed to open library dependency project file: " + - libDomainFile.getPathname()); - } - catch (VersionException e) { - log.appendMsg( - "Referenced external program requires updgrade, unable to consider symbols: " + - libPath); - } - } - - // Resolve symbols - try { - ExternalSymbolResolver.fixUnresolvedExternalSymbols(loadedPrograms, false, log, - monitor); return true; } - catch (IOException e) { - return false; - } - finally { - for (int i = 1; i < loadedPrograms.size(); i++) { - loadedPrograms.get(i).release(consumer); - } - } } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/ElfLoader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/ElfLoader.java index 6a29468f8b..e5766b1bab 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/ElfLoader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/ElfLoader.java @@ -158,8 +158,16 @@ public class ElfLoader extends AbstractLibrarySupportLoader { throws CancelledException, IOException { super.postLoadProgramFixups(loadedPrograms, project, options, messageLog, monitor); - ExternalSymbolResolver.fixUnresolvedExternalSymbols(loadedPrograms, true, messageLog, - monitor); + try (ExternalSymbolResolver esr = + new ExternalSymbolResolver(project.getProjectData(), monitor)) { + for (Loaded loadedProgram : loadedPrograms) { + esr.addProgramToFixup( + loadedProgram.getProjectFolderPath() + loadedProgram.getName(), + loadedProgram.getDomainObject()); + } + esr.fixUnresolvedExternalSymbols(); + esr.logInfo(messageLog::appendMsg, true); + } } @Override diff --git a/Ghidra/Features/Base/src/main/java/ghidra/program/util/ExternalSymbolResolver.java b/Ghidra/Features/Base/src/main/java/ghidra/program/util/ExternalSymbolResolver.java index ecd5e082e1..fca63acbcd 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/program/util/ExternalSymbolResolver.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/program/util/ExternalSymbolResolver.java @@ -15,13 +15,13 @@ */ package ghidra.program.util; +import java.io.Closeable; import java.io.IOException; import java.util.*; -import java.util.stream.Collectors; +import java.util.function.Consumer; import db.Transaction; -import ghidra.app.util.importer.MessageLog; -import ghidra.app.util.opinion.Loaded; +import ghidra.framework.model.*; import ghidra.framework.options.Options; import ghidra.program.model.listing.*; import ghidra.program.model.symbol.*; @@ -30,8 +30,15 @@ import ghidra.util.StringUtilities; import ghidra.util.exception.*; import ghidra.util.task.TaskMonitor; -public class ExternalSymbolResolver { - +/** + * Moves dangling external function symbols found in the {@link Library#UNKNOWN EXTERNAL/UNKNOWN} + * namespace into the namespace of the external library that publishes a matching symbol. + *

+ * This uses an ordered list of external library names that was attached to the program during + * import by the Elf or Macho loader (see {@link #REQUIRED_LIBRARY_PROPERTY_PREFIX}). + * + */ +public class ExternalSymbolResolver implements Closeable { private final static String REQUIRED_LIBRARY_PROPERTY_PREFIX = "Required Library ["; /** @@ -45,127 +52,415 @@ public class ExternalSymbolResolver { StringUtilities.pad("" + libraryIndex, ' ', 4)); } + private final ProjectData projectData; + private final TaskMonitor monitor; + private final List programsToFix = new ArrayList<>(); + private final Map loadedPrograms = new HashMap<>(); + private final Map problemLibraries = new HashMap<>(); + + public ExternalSymbolResolver(ProjectData projectData, TaskMonitor monitor) { + this.projectData = projectData; + this.monitor = monitor; + } + /** - * Links unresolved symbols to the first symbol found in the (ordered) linked - * libraries (saved in the program's properties as {@value #REQUIRED_LIBRARY_PROPERTY_PREFIX}). + * Queues a program into this session that will be fixed when {@link #fixUnresolvedExternalSymbols()} + * is called. *

- * The ordering and precedence logic is loader specific though no particular binary formats - * are parsed or required. - *

- * The program's external libraries need to already be populated with paths to - * already existing / imported libraries. - * - * @param loadedPrograms The {@link Loaded} {@link Program}s to fix. The first entry is the - * "primary" {@link Loaded} {@link Program}. - * @param fixAll True if all of the {@link Loaded} {@link Program}s should be fixed; - * false if just the "primary" {@link Loaded} {@link Program} should be fixed. - * @param messageLog {@link MessageLog} to write info message to. - * @param monitor {@link TaskMonitor} to watch for cancel and update with progress. - * @throws CancelledException if user cancels - * @throws IOException if error reading + * The program should be fully persisted to the project if using this method, otherwise use + * {@link #addProgramToFixup(String, Program)} and specify the pathname the program will + * be saved to. + * + * @param program {@link Program} to fix */ - public static void fixUnresolvedExternalSymbols(List> loadedPrograms, - boolean fixAll, MessageLog messageLog, TaskMonitor monitor) - throws CancelledException, IOException { - Map> loadedByPath = loadedPrograms.stream() - .collect(Collectors.toMap( - loaded -> loaded.getProjectFolderPath() + loaded.getName(), loaded -> loaded)); + public void addProgramToFixup(Program program) { + addProgramToFixup(program.getDomainFile().getPathname(), program); + } - List> fixupList = - loadedPrograms.subList(0, fixAll ? loadedPrograms.size() : 1); + /** + * Queues a program into this session that will be fixed when {@link #fixUnresolvedExternalSymbols()} + * is called. + * + * @param programPath string project path to the program + * @param program {@link Program} to fix + */ + public void addProgramToFixup(String programPath, Program program) { + programsToFix.add(new ProgramSymbolResolver(program, programPath)); + addLoadedProgram(programPath, program); + } - monitor.initialize(fixupList.size()); - for (Loaded loadedProgram : fixupList) { - Program program = loadedProgram.getDomainObject(); + /** + * Adds an already opened program to this session, allowing it to be used as an external + * library without needing to look it up in the current project. + * + * @param programPath project path to already opened program + * @param program {@link Program} + */ + public void addLoadedProgram(String programPath, Program program) { + if (loadedPrograms.put(programPath, program) == null) { + program.addConsumer(this); + } + } - Collection unresolvedExternalFunctionIds = - getUnresolvedExternalFunctionIds(program); - if (unresolvedExternalFunctionIds.size() == 0) { - continue; + /** + * Returns true if there was an error encountered when trying to open an external library. + * + * @return boolean flag, true if there was a problem opening an external library + */ + public boolean hasProblemLibraries() { + return !problemLibraries.isEmpty(); + } + + @Override + public void close() { + for (Program prog : loadedPrograms.values()) { + prog.release(this); + } + programsToFix.clear(); + loadedPrograms.clear(); + } + + /** + * Resolves any unresolved external symbols in each program that has been queued up via + * {@link #addProgramToFixup(String, Program)}. + * + * @throws CancelledException if cancelled + */ + public void fixUnresolvedExternalSymbols() throws CancelledException { + for (ProgramSymbolResolver psr : programsToFix) { + psr.resolveExternalSymbols(); + } + } + + /** + * Logs information about the libraries and symbols that were found during the fixup. + * + * @param logger consumer that will log a string + * @param shortSummary boolean flag, if true individual symbol names will be omitted + */ + public void logInfo(Consumer logger, boolean shortSummary) { + for (ProgramSymbolResolver psr : programsToFix) { + psr.log(logger, shortSummary); + } + } + + /** + * Fetches a program from a cache of Program instances. If the requested program + * isn't currently in the cache, it will be opened (if possible). + *

+ * This cache of programs are pinned by registering a consumer on the program, and will be + * released during {@link #close()} of this ExternalSymbolServer instance. + *

+ * This cache is shared between all ProgramSymbolResolver instances (that were created + * by calling {@link #addProgramToFixup(String, Program)}). + * + * @param libPath project path to a library program + * @return {@link Program}, or null if not found or other error during opening + * @throws CancelledException if cancelled + */ + protected Program getLibraryProgram(String libPath) throws CancelledException { + Program result = loadedPrograms.get(libPath); + if (result == null && !problemLibraries.containsKey(libPath)) { + result = openLibraryFile(projectData.getFile(libPath), libPath); + + if (result != null) { + loadedPrograms.put(libPath, result); } + } + return result; + } - List libSearchList = getLibrarySearchList(program); - if (libSearchList.isEmpty()) { - continue; + /** + * Opens a library binary. + * + * @param libDf optional, reference to a the DomainFile that was found in a project. If null + * (meaning a lookup in the project failed to find a matching file), libPath will be used when + * creating error strings that reference the problematic file + * @param libPath project path for the DomainFile + * @return a opened {@link Program} + * @throws CancelledException if cancelled + */ + protected Program openLibraryFile(DomainFile libDf, String libPath) throws CancelledException { + try { + if (libDf == null) { + throw new IOException("Dangling external path: " + libPath); } + DomainObject libDo = libDf.getDomainObject(this, false, false, monitor); + if (libDo instanceof Program p) { + return p; + } + libDo.release(this); + throw new IOException("Referenced external program is not a program: " + libPath); + } + catch (IOException | VersionException e) { + problemLibraries.put(libPath, e); + } + return null; + } - try (Transaction tx = program.openTransaction("Resolve External Symbols")) { - - messageLog.appendMsg("----- [" + program.getName() + "] Resolve " + - unresolvedExternalFunctionIds.size() + " external symbols -----"); - - for (Library extLibrary : libSearchList) { - monitor.checkCancelled(); - String libName = extLibrary.getName(); - String libPath = extLibrary.getAssociatedProgramPath(); - if (libPath == null) { - continue; - } - - Loaded loadedLib = loadedByPath.get(libPath); - if (loadedLib == null) { - messageLog.appendMsg("Referenced external program not found: " + libName); - continue; - } - - Program libProgram = loadedLib.getDomainObject(); - monitor.setMessage("Resolving symbols published by library " + libName); - resolveSymbolsToLibrary(program, unresolvedExternalFunctionIds, extLibrary, - libProgram, messageLog, monitor); + /** + * Represents a program that needs its external symbols to be fixed. + */ + private class ProgramSymbolResolver { + record ExtLibInfo(String name, Library lib, String programPath, Program program, + List resolvedSymbols, Throwable problem) { + String getProblemMessage() { + if (problem instanceof VersionException ve) { + return getVersionError(ve); + } + return problem != null ? problem.getMessage() : ""; + } + + String getLibPath() { + return programPath != null ? programPath : "missing"; + } + + String getVersionError(VersionException ve) { + String versionType = switch (ve.getVersionIndicator()) { + case VersionException.NEWER_VERSION -> " newer"; + case VersionException.OLDER_VERSION -> "n older"; + default -> "n unknown"; + }; + + String upgradeMsg = ve.isUpgradable() ? " (upgrade is possible)" : ""; + + return "skipped: file was created with a%s version of Ghidra%s" + .formatted(versionType, upgradeMsg); + } + + } + + Program program; + String programPath; + int externalSymbolCount; + List unresolvedExternalFunctionIds; + List extLibs = new ArrayList<>(); + + private ProgramSymbolResolver(Program program, String programPath) { + this.program = program; + this.programPath = programPath; + } + + private int getResolvedSymbolCount() { + return externalSymbolCount - unresolvedExternalFunctionIds.size(); + } + + private void log(Consumer logger, boolean shortSummary) { + boolean changed = unresolvedExternalFunctionIds.size() != externalSymbolCount; + if (extLibs.isEmpty() && externalSymbolCount == 0) { + return; + } + else if (!changed && !hasSomeLibrariesConfigured()) { + logger.accept( + "Resolving External Symbols of [%s] - %d unresolved symbols, no external libraries configured - skipping" + .formatted(programPath, externalSymbolCount)); + return; + } + + logger.accept("Resolving External Symbols of [%s]%s".formatted(programPath, + shortSummary ? " - Summary" : "")); + logger.accept("\t%d external symbols resolved, %d remain unresolved" + .formatted(getResolvedSymbolCount(), unresolvedExternalFunctionIds.size())); + for (ExtLibInfo extLib : extLibs) { + if (extLib.problem != null) { + logger.accept("\t[%s] -> %s, %s".formatted(extLib.name, extLib.getLibPath(), + extLib.getProblemMessage())); + } + else if (extLib.programPath != null) { + logger.accept("\t[%s] -> %s, %d new symbols resolved".formatted(extLib.name, + extLib.getLibPath(), extLib.resolvedSymbols.size())); + } + else { + logger.accept("\t[%s] -> %s".formatted(extLib.name, extLib.getLibPath())); + } + if (!shortSummary) { + for (String symbolName : extLib.resolvedSymbols) { + logger.accept("\t\t[%s]".formatted(symbolName)); + } + } + } + if (!shortSummary && changed) { + if (!unresolvedExternalFunctionIds.isEmpty()) { + logger.accept("\tUnresolved remaining %d:" + .formatted(unresolvedExternalFunctionIds.size())); + SymbolTable symbolTable = program.getSymbolTable(); + for (Long symId : unresolvedExternalFunctionIds) { + Symbol s = symbolTable.getSymbol(symId); + logger.accept("\t\t[%s]".formatted(s.getName())); + } } - messageLog.appendMsg("Unresolved external symbols which remain: " + - unresolvedExternalFunctionIds.size()); } } + + private boolean hasSomeLibrariesConfigured() { + for (ExtLibInfo extLib : extLibs) { + if (extLib.program != null || extLib.problem != null || + extLib.programPath != null) { + return true; + } + } + return false; + } + + private void resolveExternalSymbols() throws CancelledException { + unresolvedExternalFunctionIds = getUnresolvedExternalFunctionIds(); + externalSymbolCount = unresolvedExternalFunctionIds.size(); + + if (unresolvedExternalFunctionIds.isEmpty()) { + return; + } + + extLibs = getLibsToSearch(); + + if (!extLibs.isEmpty()) { + try (Transaction tx = program.openTransaction("Resolve External Symbols")) { + for (ExtLibInfo extLib : extLibs) { + monitor.checkCancelled(); + resolveSymbolsToLibrary(extLib); + } + } + } + + } + + /** + * Returns an ordered list of external libraries that need to be searched. + * + * @return list of ExtLibInfo elements, each representing an external library dependency + * found in the {@link #program} + * @throws CancelledException if cancelled + */ + private List getLibsToSearch() throws CancelledException { + List result = new ArrayList<>(); + ExternalManager externalManager = program.getExternalManager(); + for (String libName : getOrderedRequiredLibraryNames()) { + Library lib = externalManager.getExternalLibrary(libName); + String libPath = lib != null ? lib.getAssociatedProgramPath() : null; + Program libProg = libPath != null ? getLibraryProgram(libPath) : null; + Throwable problem = + libProg == null && libPath != null ? problemLibraries.get(libPath) : null; + + result.add( + new ExtLibInfo(libName, lib, libPath, libProg, new ArrayList<>(), problem)); + } + return result; + } + + /** + * Moves unresolved functions from the EXTERNAL/UNKNOWN namespace to the namespace of the + * external library if the extLib publishes a symbol with a matching name. + * + * @param extLib {@link ExtLibInfo} representing an external library + * @throws CancelledException if cancelled + */ + private void resolveSymbolsToLibrary(ExtLibInfo extLib) throws CancelledException { + if (extLib.program == null) { + // can't do anything if the external library doesn't have a valid program associated + return; + } + ExternalManager externalManager = program.getExternalManager(); + SymbolTable symbolTable = program.getSymbolTable(); + + for (Iterator idIterator = unresolvedExternalFunctionIds.iterator(); idIterator + .hasNext();) { + monitor.checkCancelled(); + Symbol s = symbolTable.getSymbol(idIterator.next()); + if (s == null || !s.isExternal() || s.getSymbolType() != SymbolType.FUNCTION) { + Msg.error(ExternalSymbolResolver.class, + "Concurrent modification of symbol table while resolving external symbols"); + idIterator.remove(); + continue; + } + + ExternalLocation extLoc = externalManager.getExternalLocation(s); + String extLocName = + Objects.requireNonNullElse(extLoc.getOriginalImportedName(), extLoc.getLabel()); + if (isExportedSymbol(extLib.program, extLocName)) { + try { + s.setNamespace(extLib.lib); + idIterator.remove(); + extLib.resolvedSymbols.add(s.getName()); + } + catch (DuplicateNameException | InvalidInputException + | CircularDependencyException e) { + Msg.error(ExternalSymbolResolver.class, + "Error setting external symbol namespace for " + extLoc.getLabel(), e); + } + } + } + } + + /** + * Returns a list of all external functions under the EXTERNAL/UNKNOWN library. + * + * @return list of func ids that need to be fixed + */ + private List getUnresolvedExternalFunctionIds() { + List symbolIds = new ArrayList<>(); + ExternalManager externalManager = program.getExternalManager(); + Library library = externalManager.getExternalLibrary(Library.UNKNOWN); + if (library != null) { + for (Symbol s : program.getSymbolTable().getSymbols(library)) { + if (s.getSymbolType() == SymbolType.FUNCTION && + s.getSource() != SourceType.DEFAULT) { + symbolIds.add(s.getID()); + } + } + } + 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 getOrderedRequiredLibraryNames() { + TreeMap 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(); + } + } - private static void resolveSymbolsToLibrary(Program program, - Collection unresolvedExternalFunctionIds, Library extLibrary, Program libProgram, - MessageLog messageLog, TaskMonitor monitor) throws CancelledException { - int libResolvedCount = 0; - ExternalManager externalManager = program.getExternalManager(); - SymbolTable symbolTable = program.getSymbolTable(); + /** + * Returns true if the specified program publishes a symbol with the specified name. + * + * @param program {@link Program} + * @param name symbol name + * @return true if program publishes a symbol the specified name + */ + private static boolean isExportedSymbol(Program program, String name) { - Iterator idIterator = unresolvedExternalFunctionIds.iterator(); - while (idIterator.hasNext()) { - monitor.checkCancelled(); - Symbol s = symbolTable.getSymbol(idIterator.next()); - if (s == null || !s.isExternal() || s.getSymbolType() != SymbolType.FUNCTION) { - Msg.error(ExternalSymbolResolver.class, - "Concurrent modification of symbol table while resolving external symbols"); - idIterator.remove(); - continue; - } - - ExternalLocation extLoc = externalManager.getExternalLocation(s); - if (s.getSource() == SourceType.DEFAULT || - !isLocationContainedInLibrary(libProgram, extLoc)) { - continue; - } - try { - s.setNamespace(extLibrary); - idIterator.remove(); - libResolvedCount++; - Msg.debug(ExternalSymbolResolver.class, "External symbol " + extLoc.getLabel() + - " resolved to " + extLibrary.getName()); - } - catch (DuplicateNameException | InvalidInputException | CircularDependencyException e) { - Msg.error(ExternalSymbolResolver.class, - "Error setting external symbol namespace for " + extLoc.getLabel(), e); - } - } - messageLog.appendMsg( - "Resolved " + libResolvedCount + " symbols to library " + extLibrary.getName()); - } - - private static boolean isLocationContainedInLibrary(Program libProgram, - ExternalLocation extLoc) { - - String name = extLoc.getOriginalImportedName(); - if (name == null) { - name = extLoc.getLabel(); - } - for (Symbol s : libProgram.getSymbolTable().getLabelOrFunctionSymbols(name, null)) { + for (Symbol s : program.getSymbolTable().getLabelOrFunctionSymbols(name, null)) { if (s.isExternalEntryPoint()) { return true; } @@ -173,61 +468,4 @@ public class ExternalSymbolResolver { return false; } - private static Collection getUnresolvedExternalFunctionIds(Program program) { - List symbolIds = new ArrayList<>(); - ExternalManager externalManager = program.getExternalManager(); - Library library = externalManager.getExternalLibrary(Library.UNKNOWN); - if (library != null) { - for (Symbol s : program.getSymbolTable().getSymbols(library)) { - if (s.getSymbolType() == SymbolType.FUNCTION) { - symbolIds.add(s.getID()); - } - } - } - return symbolIds; - } - - private static Collection getOrderedLibraryNamesNeeded(Program program) { - TreeMap 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(); - } - - public static List getLibrarySearchList(Program program) { - List result = new ArrayList<>(); - ExternalManager externalManager = program.getExternalManager(); - for (String libName : getOrderedLibraryNamesNeeded(program)) { - Library lib = externalManager.getExternalLibrary(libName); - if (lib != null) { - result.add(lib); - } - } - return result; - } }