15
15
*/
16
16
package ghidra .program .util ;
17
17
18
+ import java .io .Closeable ;
18
19
import java .io .IOException ;
19
20
import java .util .*;
20
- import java .util .stream . Collectors ;
21
+ import java .util .function . Consumer ;
21
22
22
23
import db .Transaction ;
23
- import ghidra .app .util .importer .MessageLog ;
24
- import ghidra .app .util .opinion .Loaded ;
24
+ import ghidra .framework .model .*;
25
25
import ghidra .framework .options .Options ;
26
26
import ghidra .program .model .listing .*;
27
27
import ghidra .program .model .symbol .*;
30
30
import ghidra .util .exception .*;
31
31
import ghidra .util .task .TaskMonitor ;
32
32
33
- public class ExternalSymbolResolver {
34
-
33
+ /**
34
+ * Moves dangling external function symbols found in the {@link Library#UNKNOWN EXTERNAL/UNKNOWN}
35
+ * namespace into the namespace of the external library that publishes a matching symbol.
36
+ * <p>
37
+ * This uses an ordered list of external library names that was attached to the program during
38
+ * import by the Elf or Macho loader (see {@link #REQUIRED_LIBRARY_PROPERTY_PREFIX}).
39
+ *
40
+ */
41
+ public class ExternalSymbolResolver implements Closeable {
35
42
private final static String REQUIRED_LIBRARY_PROPERTY_PREFIX = "Required Library [" ;
36
43
37
44
/**
@@ -45,189 +52,420 @@ public static String getRequiredLibraryProperty(int libraryIndex) {
45
52
StringUtilities .pad ("" + libraryIndex , ' ' , 4 ));
46
53
}
47
54
55
+ private final ProjectData projectData ;
56
+ private final TaskMonitor monitor ;
57
+ private final List <ProgramSymbolResolver > programsToFix = new ArrayList <>();
58
+ private final Map <String , Program > loadedPrograms = new HashMap <>();
59
+ private final Map <String , Throwable > problemLibraries = new HashMap <>();
60
+
61
+ public ExternalSymbolResolver (ProjectData projectData , TaskMonitor monitor ) {
62
+ this .projectData = projectData ;
63
+ this .monitor = monitor ;
64
+ }
65
+
66
+ /**
67
+ * Queues a program into this session that will be fixed when {@link #fixUnresolvedExternalSymbols()}
68
+ * is called.
69
+ * <p>
70
+ * The program should be fully persisted to the project if using this method, otherwise use
71
+ * {@link #addProgramToFixup(String, Program)} and specify the pathname the program will
72
+ * be saved to.
73
+ *
74
+ * @param program {@link Program} to fix
75
+ */
76
+ public void addProgramToFixup (Program program ) {
77
+ addProgramToFixup (program .getDomainFile ().getPathname (), program );
78
+ }
79
+
80
+ /**
81
+ * Queues a program into this session that will be fixed when {@link #fixUnresolvedExternalSymbols()}
82
+ * is called.
83
+ *
84
+ * @param programPath string project path to the program
85
+ * @param program {@link Program} to fix
86
+ */
87
+ public void addProgramToFixup (String programPath , Program program ) {
88
+ programsToFix .add (new ProgramSymbolResolver (program , programPath ));
89
+ addLoadedProgram (programPath , program );
90
+ }
91
+
92
+ /**
93
+ * Adds an already opened program to this session, allowing it to be used as an external
94
+ * library without needing to look it up in the current project.
95
+ *
96
+ * @param programPath project path to already opened program
97
+ * @param program {@link Program}
98
+ */
99
+ public void addLoadedProgram (String programPath , Program program ) {
100
+ if (loadedPrograms .put (programPath , program ) == null ) {
101
+ program .addConsumer (this );
102
+ }
103
+ }
104
+
105
+ /**
106
+ * Returns true if there was an error encountered when trying to open an external library.
107
+ *
108
+ * @return boolean flag, true if there was a problem opening an external library
109
+ */
110
+ public boolean hasProblemLibraries () {
111
+ return !problemLibraries .isEmpty ();
112
+ }
113
+
114
+ @ Override
115
+ public void close () {
116
+ for (Program prog : loadedPrograms .values ()) {
117
+ prog .release (this );
118
+ }
119
+ programsToFix .clear ();
120
+ loadedPrograms .clear ();
121
+ }
122
+
123
+ /**
124
+ * Resolves any unresolved external symbols in each program that has been queued up via
125
+ * {@link #addProgramToFixup(String, Program)}.
126
+ *
127
+ * @throws CancelledException if cancelled
128
+ */
129
+ public void fixUnresolvedExternalSymbols () throws CancelledException {
130
+ for (ProgramSymbolResolver psr : programsToFix ) {
131
+ psr .resolveExternalSymbols ();
132
+ }
133
+ }
134
+
48
135
/**
49
- * Links unresolved symbols to the first symbol found in the (ordered) linked
50
- * libraries (saved in the program's properties as {@value #REQUIRED_LIBRARY_PROPERTY_PREFIX}).
136
+ * Logs information about the libraries and symbols that were found during the fixup.
137
+ *
138
+ * @param logger consumer that will log a string
139
+ * @param shortSummary boolean flag, if true individual symbol names will be omitted
140
+ */
141
+ public void logInfo (Consumer <String > logger , boolean shortSummary ) {
142
+ for (ProgramSymbolResolver psr : programsToFix ) {
143
+ psr .log (logger , shortSummary );
144
+ }
145
+ }
146
+
147
+ /**
148
+ * Fetches a program from a cache of Program instances. If the requested program
149
+ * isn't currently in the cache, it will be opened (if possible).
51
150
* <p>
52
- * The ordering and precedence logic is loader specific though no particular binary formats
53
- * are parsed or required .
151
+ * This cache of programs are pinned by registering a consumer on the program, and will be
152
+ * released during {@link #close()} of this ExternalSymbolServer instance .
54
153
* <p>
55
- * The program's external libraries need to already be populated with paths to
56
- * already existing / imported libraries.
57
- *
58
- * @param loadedPrograms The {@link Loaded} {@link Program}s to fix. The first entry is the
59
- * "primary" {@link Loaded} {@link Program}.
60
- * @param fixAll True if all of the {@link Loaded} {@link Program}s should be fixed;
61
- * false if just the "primary" {@link Loaded} {@link Program} should be fixed.
62
- * @param messageLog {@link MessageLog} to write info message to.
63
- * @param monitor {@link TaskMonitor} to watch for cancel and update with progress.
64
- * @throws CancelledException if user cancels
65
- * @throws IOException if error reading
154
+ * This cache is shared between all ProgramSymbolResolver instances (that were created
155
+ * by calling {@link #addProgramToFixup(String, Program)}).
156
+ *
157
+ * @param libPath project path to a library program
158
+ * @return {@link Program}, or null if not found or other error during opening
159
+ * @throws CancelledException if cancelled
66
160
*/
67
- public static void fixUnresolvedExternalSymbols (List <Loaded <Program >> loadedPrograms ,
68
- boolean fixAll , MessageLog messageLog , TaskMonitor monitor )
69
- throws CancelledException , IOException {
70
- Map <String , Loaded <Program >> loadedByPath = loadedPrograms .stream ()
71
- .collect (Collectors .toMap (
72
- loaded -> loaded .getProjectFolderPath () + loaded .getName (), loaded -> loaded ));
161
+ protected Program getLibraryProgram (String libPath ) throws CancelledException {
162
+ Program result = loadedPrograms .get (libPath );
163
+ if (result == null && !problemLibraries .containsKey (libPath )) {
164
+ result = openLibraryFile (projectData .getFile (libPath ), libPath );
165
+
166
+ if (result != null ) {
167
+ loadedPrograms .put (libPath , result );
168
+ }
169
+ }
170
+ return result ;
171
+ }
73
172
74
- List <Loaded <Program >> fixupList =
75
- loadedPrograms .subList (0 , fixAll ? loadedPrograms .size () : 1 );
173
+ /**
174
+ * Opens a library binary.
175
+ *
176
+ * @param libDf optional, reference to a the DomainFile that was found in a project. If null
177
+ * (meaning a lookup in the project failed to find a matching file), libPath will be used when
178
+ * creating error strings that reference the problematic file
179
+ * @param libPath project path for the DomainFile
180
+ * @return a opened {@link Program}
181
+ * @throws CancelledException if cancelled
182
+ */
183
+ protected Program openLibraryFile (DomainFile libDf , String libPath ) throws CancelledException {
184
+ try {
185
+ if (libDf == null ) {
186
+ throw new IOException ("Dangling external path: " + libPath );
187
+ }
188
+ DomainObject libDo = libDf .getDomainObject (this , false , false , monitor );
189
+ if (libDo instanceof Program p ) {
190
+ return p ;
191
+ }
192
+ libDo .release (this );
193
+ throw new IOException ("Referenced external program is not a program: " + libPath );
194
+ }
195
+ catch (IOException | VersionException e ) {
196
+ problemLibraries .put (libPath , e );
197
+ }
198
+ return null ;
199
+ }
76
200
77
- monitor .initialize (fixupList .size ());
78
- for (Loaded <Program > loadedProgram : fixupList ) {
79
- Program program = loadedProgram .getDomainObject ();
201
+ /**
202
+ * Represents a program that needs its external symbols to be fixed.
203
+ */
204
+ private class ProgramSymbolResolver {
205
+ record ExtLibInfo (String name , Library lib , String programPath , Program program ,
206
+ List <String > resolvedSymbols , Throwable problem ) {
207
+ String getProblemMessage () {
208
+ if (problem instanceof VersionException ve ) {
209
+ return getVersionError (ve );
210
+ }
211
+ return problem != null ? problem .getMessage () : "" ;
212
+ }
80
213
81
- Collection <Long > unresolvedExternalFunctionIds =
82
- getUnresolvedExternalFunctionIds (program );
83
- if (unresolvedExternalFunctionIds .size () == 0 ) {
84
- continue ;
214
+ String getLibPath () {
215
+ return programPath != null ? programPath : "missing" ;
85
216
}
86
217
87
- List <Library > libSearchList = getLibrarySearchList (program );
88
- if (libSearchList .isEmpty ()) {
89
- continue ;
218
+ String getVersionError (VersionException ve ) {
219
+ String versionType = switch (ve .getVersionIndicator ()) {
220
+ case VersionException .NEWER_VERSION -> " newer" ;
221
+ case VersionException .OLDER_VERSION -> "n older" ;
222
+ default -> "n unknown" ;
223
+ };
224
+
225
+ String upgradeMsg = ve .isUpgradable () ? " (upgrade is possible)" : "" ;
226
+
227
+ return "skipped: file was created with a%s version of Ghidra%s"
228
+ .formatted (versionType , upgradeMsg );
90
229
}
91
230
92
- try (Transaction tx = program .openTransaction ("Resolve External Symbols" )) {
231
+ }
232
+
233
+ Program program ;
234
+ String programPath ;
235
+ int externalSymbolCount ;
236
+ List <Long > unresolvedExternalFunctionIds ;
237
+ List <ExtLibInfo > extLibs = new ArrayList <>();
238
+
239
+ private ProgramSymbolResolver (Program program , String programPath ) {
240
+ this .program = program ;
241
+ this .programPath = programPath ;
242
+ }
93
243
94
- messageLog .appendMsg ("----- [" + program .getName () + "] Resolve " +
95
- unresolvedExternalFunctionIds .size () + " external symbols -----" );
244
+ private int getResolvedSymbolCount () {
245
+ return externalSymbolCount - unresolvedExternalFunctionIds .size ();
246
+ }
96
247
97
- for (Library extLibrary : libSearchList ) {
98
- monitor .checkCancelled ();
99
- String libName = extLibrary .getName ();
100
- String libPath = extLibrary .getAssociatedProgramPath ();
101
- if (libPath == null ) {
102
- continue ;
248
+ private void log (Consumer <String > logger , boolean shortSummary ) {
249
+ boolean changed = unresolvedExternalFunctionIds .size () != externalSymbolCount ;
250
+ if (extLibs .isEmpty () && externalSymbolCount == 0 ) {
251
+ return ;
252
+ }
253
+ else if (!changed && !hasSomeLibrariesConfigured ()) {
254
+ logger .accept (
255
+ "Resolving External Symbols of [%s] - %d unresolved symbols, no external libraries configured - skipping"
256
+ .formatted (programPath , externalSymbolCount ));
257
+ return ;
258
+ }
259
+
260
+ logger .accept ("Resolving External Symbols of [%s]%s" .formatted (programPath ,
261
+ shortSummary ? " - Summary" : "" ));
262
+ logger .accept ("\t %d external symbols resolved, %d remain unresolved"
263
+ .formatted (getResolvedSymbolCount (), unresolvedExternalFunctionIds .size ()));
264
+ for (ExtLibInfo extLib : extLibs ) {
265
+ if (extLib .problem != null ) {
266
+ logger .accept ("\t [%s] -> %s, %s" .formatted (extLib .name , extLib .getLibPath (),
267
+ extLib .getProblemMessage ()));
268
+ }
269
+ else if (extLib .programPath != null ) {
270
+ logger .accept ("\t [%s] -> %s, %d new symbols resolved" .formatted (extLib .name ,
271
+ extLib .getLibPath (), extLib .resolvedSymbols .size ()));
272
+ }
273
+ else {
274
+ logger .accept ("\t [%s] -> %s" .formatted (extLib .name , extLib .getLibPath ()));
275
+ }
276
+ if (!shortSummary ) {
277
+ for (String symbolName : extLib .resolvedSymbols ) {
278
+ logger .accept ("\t \t [%s]" .formatted (symbolName ));
103
279
}
104
-
105
- Loaded <Program > loadedLib = loadedByPath .get (libPath );
106
- if (loadedLib == null ) {
107
- messageLog .appendMsg ("Referenced external program not found: " + libName );
108
- continue ;
280
+ }
281
+ }
282
+ if (!shortSummary && changed ) {
283
+ if (!unresolvedExternalFunctionIds .isEmpty ()) {
284
+ logger .accept ("\t Unresolved remaining %d:"
285
+ .formatted (unresolvedExternalFunctionIds .size ()));
286
+ SymbolTable symbolTable = program .getSymbolTable ();
287
+ for (Long symId : unresolvedExternalFunctionIds ) {
288
+ Symbol s = symbolTable .getSymbol (symId );
289
+ logger .accept ("\t \t [%s]" .formatted (s .getName ()));
109
290
}
110
-
111
- Program libProgram = loadedLib .getDomainObject ();
112
- monitor .setMessage ("Resolving symbols published by library " + libName );
113
- resolveSymbolsToLibrary (program , unresolvedExternalFunctionIds , extLibrary ,
114
- libProgram , messageLog , monitor );
115
291
}
116
- messageLog .appendMsg ("Unresolved external symbols which remain: " +
117
- unresolvedExternalFunctionIds .size ());
118
292
}
119
293
}
120
- }
121
294
122
- private static void resolveSymbolsToLibrary (Program program ,
123
- Collection <Long > unresolvedExternalFunctionIds , Library extLibrary , Program libProgram ,
124
- MessageLog messageLog , TaskMonitor monitor ) throws CancelledException {
125
- int libResolvedCount = 0 ;
126
- ExternalManager externalManager = program .getExternalManager ();
127
- SymbolTable symbolTable = program .getSymbolTable ();
128
-
129
- Iterator <Long > idIterator = unresolvedExternalFunctionIds .iterator ();
130
- while (idIterator .hasNext ()) {
131
- monitor .checkCancelled ();
132
- Symbol s = symbolTable .getSymbol (idIterator .next ());
133
- if (s == null || !s .isExternal () || s .getSymbolType () != SymbolType .FUNCTION ) {
134
- Msg .error (ExternalSymbolResolver .class ,
135
- "Concurrent modification of symbol table while resolving external symbols" );
136
- idIterator .remove ();
137
- continue ;
138
- }
139
-
140
- ExternalLocation extLoc = externalManager .getExternalLocation (s );
141
- if (s .getSource () == SourceType .DEFAULT ||
142
- !isLocationContainedInLibrary (libProgram , extLoc )) {
143
- continue ;
144
- }
145
- try {
146
- s .setNamespace (extLibrary );
147
- idIterator .remove ();
148
- libResolvedCount ++;
149
- Msg .debug (ExternalSymbolResolver .class , "External symbol " + extLoc .getLabel () +
150
- " resolved to " + extLibrary .getName ());
151
- }
152
- catch (DuplicateNameException | InvalidInputException | CircularDependencyException e ) {
153
- Msg .error (ExternalSymbolResolver .class ,
154
- "Error setting external symbol namespace for " + extLoc .getLabel (), e );
155
- }
156
- }
157
- messageLog .appendMsg (
158
- "Resolved " + libResolvedCount + " symbols to library " + extLibrary .getName ());
159
- }
295
+ private boolean hasSomeLibrariesConfigured () {
296
+ for (ExtLibInfo extLib : extLibs ) {
297
+ if (extLib .program != null || extLib .problem != null ||
298
+ extLib .programPath != null ) {
299
+ return true ;
300
+ }
301
+ }
302
+ return false ;
303
+ }
160
304
161
- private static boolean isLocationContainedInLibrary (Program libProgram ,
162
- ExternalLocation extLoc ) {
305
+ private void resolveExternalSymbols () throws CancelledException {
306
+ unresolvedExternalFunctionIds = getUnresolvedExternalFunctionIds ();
307
+ externalSymbolCount = unresolvedExternalFunctionIds .size ();
163
308
164
- String name = extLoc .getOriginalImportedName ();
165
- if (name == null ) {
166
- name = extLoc .getLabel ();
167
- }
168
- for (Symbol s : libProgram .getSymbolTable ().getLabelOrFunctionSymbols (name , null )) {
169
- if (s .isExternalEntryPoint ()) {
170
- return true ;
309
+ if (unresolvedExternalFunctionIds .isEmpty ()) {
310
+ return ;
171
311
}
172
- }
173
- return false ;
174
- }
175
312
176
- private static Collection < Long > getUnresolvedExternalFunctionIds ( Program program ) {
177
- List < Long > symbolIds = new ArrayList <>();
178
- ExternalManager externalManager = program . getExternalManager ();
179
- Library library = externalManager . getExternalLibrary ( Library . UNKNOWN );
180
- if ( library != null ) {
181
- for ( Symbol s : program . getSymbolTable (). getSymbols ( library )) {
182
- if ( s . getSymbolType () == SymbolType . FUNCTION ) {
183
- symbolIds . add ( s . getID ());
313
+ extLibs = getLibsToSearch ();
314
+
315
+ if (! extLibs . isEmpty ()) {
316
+ try ( Transaction tx = program . openTransaction ( "Resolve External Symbols" )) {
317
+ for ( ExtLibInfo extLib : extLibs ) {
318
+ monitor . checkCancelled ();
319
+ resolveSymbolsToLibrary ( extLib );
320
+ }
184
321
}
185
322
}
323
+
186
324
}
187
- return symbolIds ;
188
- }
189
325
190
- private static Collection <String > getOrderedLibraryNamesNeeded (Program program ) {
191
- TreeMap <Integer , String > orderLibraryMap = new TreeMap <>();
192
- Options options = program .getOptions (Program .PROGRAM_INFO );
193
- for (String optionName : options .getOptionNames ()) {
326
+ /**
327
+ * Returns an ordered list of external libraries that need to be searched.
328
+ *
329
+ * @return list of ExtLibInfo elements, each representing an external library dependency
330
+ * found in the {@link #program}
331
+ * @throws CancelledException if cancelled
332
+ */
333
+ private List <ExtLibInfo > getLibsToSearch () throws CancelledException {
334
+ List <ExtLibInfo > result = new ArrayList <>();
335
+ ExternalManager externalManager = program .getExternalManager ();
336
+ for (String libName : getOrderedRequiredLibraryNames ()) {
337
+ Library lib = externalManager .getExternalLibrary (libName );
338
+ String libPath = lib != null ? lib .getAssociatedProgramPath () : null ;
339
+ Program libProg = libPath != null ? getLibraryProgram (libPath ) : null ;
340
+ Throwable problem =
341
+ libProg == null && libPath != null ? problemLibraries .get (libPath ) : null ;
194
342
195
- // Legacy programs may have the old "ELF Required Library [" program property, so
196
- // we should not assume that the option name starts exactly with
197
- // REQUIRED_LIBRARY_PROPERTY_PREFIX. We must deal with a potential substring at the
198
- // start of the option name.
199
- int prefixIndex = optionName .indexOf (REQUIRED_LIBRARY_PROPERTY_PREFIX );
200
- if (prefixIndex == -1 || !optionName .endsWith ("]" )) {
201
- continue ;
343
+ result .add (
344
+ new ExtLibInfo (libName , lib , libPath , libProg , new ArrayList <>(), problem ));
202
345
}
203
- String libName = options .getString (optionName , null );
204
- if (libName == null ) {
205
- continue ;
346
+ return result ;
347
+ }
348
+
349
+ /**
350
+ * Moves unresolved functions from the EXTERNAL/UNKNOWN namespace to the namespace of the
351
+ * external library if the extLib publishes a symbol with a matching name.
352
+ *
353
+ * @param extLib {@link ExtLibInfo} representing an external library
354
+ * @throws CancelledException if cancelled
355
+ */
356
+ private void resolveSymbolsToLibrary (ExtLibInfo extLib ) throws CancelledException {
357
+ if (extLib .program == null ) {
358
+ // can't do anything if the external library doesn't have a valid program associated
359
+ return ;
206
360
}
207
- String indexStr = optionName
208
- .substring (prefixIndex + REQUIRED_LIBRARY_PROPERTY_PREFIX .length (),
209
- optionName .length () - 1 )
210
- .trim ();
211
- try {
212
- orderLibraryMap .put (Integer .parseInt (indexStr ), libName .trim ());
361
+ ExternalManager externalManager = program .getExternalManager ();
362
+ SymbolTable symbolTable = program .getSymbolTable ();
363
+
364
+ for (Iterator <Long > idIterator = unresolvedExternalFunctionIds .iterator (); idIterator
365
+ .hasNext ();) {
366
+ monitor .checkCancelled ();
367
+ Symbol s = symbolTable .getSymbol (idIterator .next ());
368
+ if (s == null || !s .isExternal () || s .getSymbolType () != SymbolType .FUNCTION ) {
369
+ Msg .error (ExternalSymbolResolver .class ,
370
+ "Concurrent modification of symbol table while resolving external symbols" );
371
+ idIterator .remove ();
372
+ continue ;
373
+ }
374
+
375
+ ExternalLocation extLoc = externalManager .getExternalLocation (s );
376
+ String extLocName =
377
+ Objects .requireNonNullElse (extLoc .getOriginalImportedName (), extLoc .getLabel ());
378
+ if (isExportedSymbol (extLib .program , extLocName )) {
379
+ try {
380
+ s .setNamespace (extLib .lib );
381
+ idIterator .remove ();
382
+ extLib .resolvedSymbols .add (s .getName ());
383
+ }
384
+ catch (DuplicateNameException | InvalidInputException
385
+ | CircularDependencyException e ) {
386
+ Msg .error (ExternalSymbolResolver .class ,
387
+ "Error setting external symbol namespace for " + extLoc .getLabel (), e );
388
+ }
389
+ }
213
390
}
214
- catch (NumberFormatException e ) {
215
- Msg .error (ExternalSymbolResolver .class ,
216
- "Program contains invalid property: " + optionName );
391
+ }
392
+
393
+ /**
394
+ * Returns a list of all external functions under the EXTERNAL/UNKNOWN library.
395
+ *
396
+ * @return list of func ids that need to be fixed
397
+ */
398
+ private List <Long > getUnresolvedExternalFunctionIds () {
399
+ List <Long > symbolIds = new ArrayList <>();
400
+ ExternalManager externalManager = program .getExternalManager ();
401
+ Library library = externalManager .getExternalLibrary (Library .UNKNOWN );
402
+ if (library != null ) {
403
+ for (Symbol s : program .getSymbolTable ().getSymbols (library )) {
404
+ if (s .getSymbolType () == SymbolType .FUNCTION &&
405
+ s .getSource () != SourceType .DEFAULT ) {
406
+ symbolIds .add (s .getID ());
407
+ }
408
+ }
409
+ }
410
+ return symbolIds ;
411
+ }
412
+
413
+ /**
414
+ * Returns an ordered list of library names, as specified by the logic/rules of the original
415
+ * operating system's loader (eg. Elf / MachO dynamic library loading / symbol resolving
416
+ * rules)
417
+ *
418
+ * @return list of library names, in original order
419
+ */
420
+ private Collection <String > getOrderedRequiredLibraryNames () {
421
+ TreeMap <Integer , String > orderLibraryMap = new TreeMap <>();
422
+ Options options = program .getOptions (Program .PROGRAM_INFO );
423
+ for (String optionName : options .getOptionNames ()) {
424
+
425
+ // Legacy programs may have the old "ELF Required Library [" program property, so
426
+ // we should not assume that the option name starts exactly with
427
+ // REQUIRED_LIBRARY_PROPERTY_PREFIX. We must deal with a potential substring at the
428
+ // start of the option name.
429
+ int prefixIndex = optionName .indexOf (REQUIRED_LIBRARY_PROPERTY_PREFIX );
430
+ if (prefixIndex == -1 || !optionName .endsWith ("]" )) {
431
+ continue ;
432
+ }
433
+ String libName = options .getString (optionName , null );
434
+ if (libName == null ) {
435
+ continue ;
436
+ }
437
+ String indexStr = optionName
438
+ .substring (prefixIndex + REQUIRED_LIBRARY_PROPERTY_PREFIX .length (),
439
+ optionName .length () - 1 )
440
+ .trim ();
441
+ try {
442
+ orderLibraryMap .put (Integer .parseInt (indexStr ), libName .trim ());
443
+ }
444
+ catch (NumberFormatException e ) {
445
+ Msg .error (ExternalSymbolResolver .class ,
446
+ "Program contains invalid property: " + optionName );
447
+ }
217
448
}
449
+ return orderLibraryMap .values ();
218
450
}
219
- return orderLibraryMap . values ();
451
+
220
452
}
221
453
222
- public static List <Library > getLibrarySearchList (Program program ) {
223
- List <Library > result = new ArrayList <>();
224
- ExternalManager externalManager = program .getExternalManager ();
225
- for (String libName : getOrderedLibraryNamesNeeded (program )) {
226
- Library lib = externalManager .getExternalLibrary (libName );
227
- if (lib != null ) {
228
- result .add (lib );
454
+ /**
455
+ * Returns true if the specified program publishes a symbol with the specified name.
456
+ *
457
+ * @param program {@link Program}
458
+ * @param name symbol name
459
+ * @return true if program publishes a symbol the specified name
460
+ */
461
+ private static boolean isExportedSymbol (Program program , String name ) {
462
+
463
+ for (Symbol s : program .getSymbolTable ().getLabelOrFunctionSymbols (name , null )) {
464
+ if (s .isExternalEntryPoint ()) {
465
+ return true ;
229
466
}
230
467
}
231
- return result ;
468
+ return false ;
232
469
}
470
+
233
471
}
0 commit comments