Merge remote-tracking branch

'origin/GP-3015_Dan_symbolsByNameAssemblerFix--REBASED-1' (Closes #2630)
This commit is contained in:
Ryan Kurtz 2023-01-26 10:58:30 -05:00
commit aa7a93f0a3
17 changed files with 801 additions and 466 deletions

View file

@ -16,7 +16,9 @@
package ghidra.app.plugin.assembler.sleigh.symbol;
import java.util.*;
import java.util.stream.Collectors;
import java.util.Map.Entry;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSpace;
@ -30,8 +32,7 @@ import ghidra.program.model.symbol.*;
* A context to hold various symbols offered to the assembler, usable where numbers are expected.
*/
public final class AssemblyNumericSymbols {
public static final AssemblyNumericSymbols EMPTY =
new AssemblyNumericSymbols(Map.of(), Map.of(), Map.of());
public static final AssemblyNumericSymbols EMPTY = new AssemblyNumericSymbols();
/**
* Collect labels derived from memory-mapped registers in a language
@ -42,7 +43,8 @@ public final class AssemblyNumericSymbols {
* @param labels the destination map
* @param language the language
*/
private static void collectLanguageLabels(Map<String, Set<Address>> labels, Language language) {
private static NavigableMap<String, Set<Address>> collectLanguageLabels(Language language) {
NavigableMap<String, Set<Address>> labels = new TreeMap<>();
for (Register reg : language.getRegisters()) {
// TODO/HACK: There ought to be a better mechanism describing suitable symbolic
// substitutions for a given operand.
@ -50,42 +52,25 @@ public final class AssemblyNumericSymbols {
labels.computeIfAbsent(reg.getName(), n -> new HashSet<>()).add(reg.getAddress());
}
}
return labels;
}
/**
* Collect labels from the program's database
*
* @param labels the destination map
* @param program the source program
*/
private static void collectProgramLabels(Map<String, Set<Address>> labels, Program program) {
final SymbolIterator it = program.getSymbolTable().getAllSymbols(true);
while (it.hasNext()) {
Symbol sym = it.next();
SymbolType symbolType = sym.getSymbolType();
if (symbolType == SymbolType.LABEL) {
if (sym.isExternal()) {
continue;
}
labels.computeIfAbsent(sym.getName(), n -> new HashSet<>()).add(sym.getAddress());
}
else if (symbolType == SymbolType.FUNCTION) {
if (!sym.getAddress().isExternalAddress()) {
labels.computeIfAbsent(sym.getName(), n -> new HashSet<>())
.add(sym.getAddress());
}
Function function = (Function) sym.getObject();
Address[] thunks = function.getFunctionThunkAddresses(true);
if (thunks != null) {
for (Address t : thunks) {
if (!t.isExternalAddress()) {
labels.computeIfAbsent(sym.getName(), n -> new HashSet<>()).add(t);
}
}
}
}
// Ignore other symbol types
private static Stream<Address> streamAddresses(Symbol sym) {
SymbolType symbolType = sym.getSymbolType();
if (symbolType == SymbolType.LABEL) {
return Stream.of(sym.getAddress());
}
if (symbolType == SymbolType.FUNCTION) {
Function function = (Function) sym.getObject();
Address[] thunks = function.getFunctionThunkAddresses(true);
return thunks == null ? Stream.of(sym.getAddress())
: Stream.concat(Stream.of(sym.getAddress()), Stream.of(thunks));
}
return Stream.of();
}
private static Stream<Address> streamNonExternalAddresses(Symbol sym) {
return streamAddresses(sym).filter(a -> !a.isExternalAddress());
}
/**
@ -94,13 +79,15 @@ public final class AssemblyNumericSymbols {
* @param equates the destination map
* @param programthe source program
*/
private static void collectProgramEquates(Map<String, Set<Long>> equates, Program program) {
private static NavigableMap<String, Set<Long>> collectProgramEquates(Program program) {
NavigableMap<String, Set<Long>> equates = new TreeMap<>();
final Iterator<Equate> it = program.getEquateTable().getEquates();
while (it.hasNext()) {
Equate eq = it.next();
// Thought is: If that's what the user sees, then that's what the user will type!
equates.computeIfAbsent(eq.getDisplayName(), n -> new HashSet<>()).add(eq.getValue());
}
return equates;
}
/**
@ -110,84 +97,60 @@ public final class AssemblyNumericSymbols {
* @return the symbols
*/
public static AssemblyNumericSymbols fromLanguage(Language language) {
Map<String, Set<Address>> labels = new HashMap<>();
collectLanguageLabels(labels, language);
return forMaps(Map.of(), labels);
return new AssemblyNumericSymbols(language);
}
/**
* Get symbols from a program (and its language)
*
* <p>
* TODO: It might be nice to cache these and use a listener to keep the maps up to date. Will
* depend on interactive performance.
*
* @param program the program
* @return the symbols
*/
public static AssemblyNumericSymbols fromProgram(Program program) {
Map<String, Set<Long>> equates = new HashMap<>();
Map<String, Set<Address>> labels = new HashMap<>();
collectLanguageLabels(labels, program.getLanguage());
collectProgramLabels(labels, program);
collectProgramEquates(equates, program);
return forMaps(equates, labels);
return new AssemblyNumericSymbols(program);
}
/**
* Get symbols for the given equate and label maps
*
* @param equates the equates
* @param labels the labels
* @return the symbols
*/
public static AssemblyNumericSymbols forMaps(Map<String, Set<Long>> equates,
Map<String, Set<Address>> labels) {
return new AssemblyNumericSymbols(Map.copyOf(equates), Map.copyOf(labels),
groupBySpace(labels));
public final NavigableMap<String, Set<Long>> programEquates;
public final NavigableMap<String, Set<Address>> languageLabels;
private final Program program;
private AssemblyNumericSymbols() {
this.program = null;
this.programEquates = new TreeMap<>();
this.languageLabels = new TreeMap<>();
}
private static Map<AddressSpace, Map<String, Set<Address>>> groupBySpace(
Map<String, Set<Address>> labels) {
Map<AddressSpace, Map<String, Set<Address>>> result = new HashMap<>();
for (Map.Entry<String, Set<Address>> entry : labels.entrySet()) {
for (Address addr : entry.getValue()) {
result.computeIfAbsent(addr.getAddressSpace(), as -> new HashMap<>())
.computeIfAbsent(entry.getKey(), k -> new TreeSet<>())
.add(addr);
}
}
return Collections.unmodifiableMap(result);
private AssemblyNumericSymbols(Language language) {
this.program = null;
this.programEquates = new TreeMap<>();
this.languageLabels = collectLanguageLabels(language);
}
private final NavigableSet<String> all = new TreeSet<>();
public final Map<String, Set<Long>> equates;
public final Map<String, Set<Address>> labels;
public final Map<AddressSpace, Map<String, Set<Address>>> labelsBySpace;
private AssemblyNumericSymbols(Map<String, Set<Long>> equates, Map<String, Set<Address>> labels,
Map<AddressSpace, Map<String, Set<Address>>> labelsBySpace) {
this.equates = equates;
this.labels = labels;
this.labelsBySpace = labelsBySpace;
all.addAll(equates.keySet());
all.addAll(labels.keySet());
private AssemblyNumericSymbols(Program program) {
this.program = program;
this.programEquates = collectProgramEquates(program);
this.languageLabels = collectLanguageLabels(program.getLanguage());
}
/**
* Choose any symbol with the given name
*
* <p>
* This will check equates first, then labels. If an equate is found, its value is returned. If
* a label is found, its addressable word offset is returned.
* This will order equates first, then program labels, then language labels. For addresses, the
* value is its addressable word offset.
*
* @param name the name
* @return the value, or null
*/
public Set<Long> chooseAll(String name) {
Set<Long> result = new TreeSet<>();
result.addAll(equates.getOrDefault(name, Set.of()));
for (Address address : labels.getOrDefault(name, Set.of())) {
result.addAll(programEquates.getOrDefault(name, Set.of()));
if (program != null) {
StreamSupport.stream(program.getSymbolTable().getSymbols(name).spliterator(), false)
.flatMap(sym -> streamNonExternalAddresses(sym))
.forEach(a -> result.add(a.getAddressableWordOffset()));
}
for (Address address : languageLabels.getOrDefault(name, Set.of())) {
result.add(address.getAddressableWordOffset());
}
return result;
@ -201,11 +164,20 @@ public final class AssemblyNumericSymbols {
* @return the addressable word offset of the found label, or null
*/
public Set<Long> chooseBySpace(String name, AddressSpace space) {
return labelsBySpace.getOrDefault(space, Map.of())
.getOrDefault(name, Set.of())
.stream()
.map(a -> a.getAddressableWordOffset())
.collect(Collectors.toSet());
Set<Long> result = new TreeSet<>();
if (program != null) {
StreamSupport.stream(program.getSymbolTable().getSymbols(name).spliterator(), false)
.flatMap(sym -> streamAddresses(sym))
.filter(a -> a.getAddressSpace() == space)
.forEach(a -> result.add(a.getAddressableWordOffset()));
}
for (Address address : languageLabels.getOrDefault(name, Set.of())) {
if (address.getAddressSpace() != space) {
continue;
}
result.add(address.getAddressableWordOffset());
}
return result;
}
/**
@ -228,23 +200,59 @@ public final class AssemblyNumericSymbols {
return chooseBySpace(name, space);
}
private Collection<String> suggestFrom(String got, Collection<String> keys, int max,
boolean sorted) {
Set<String> result = new HashSet<>();
private void suggestFrom(List<String> result, String got, NavigableSet<String> keys, int max) {
int count = 0;
for (String label : keys) {
if (count >= max) {
break;
}
if (label.startsWith(got)) {
result.add(label);
count++;
}
else if (sorted) {
break;
for (String k : keys.tailSet(got)) {
if (count >= max || !k.startsWith(got)) {
return;
}
result.add(k);
count++;
}
}
private void suggestFromBySpace(List<String> result, String got,
NavigableMap<String, Set<Address>> labels, int max, AddressSpace space) {
int count = 0;
for (Entry<String, Set<Address>> ent : labels.entrySet()) {
if (count >= max || !ent.getKey().startsWith(got)) {
return;
}
if (!ent.getValue().stream().anyMatch(a -> a.getAddressSpace() == space)) {
continue;
}
result.add(ent.getKey());
count++;
}
}
private void suggestFromProgramAny(List<String> result, String got, int max) {
int count = 0;
for (Symbol s : program.getSymbolTable().scanSymbolsByName(got)) {
if (count >= max || !s.getName().startsWith(got)) {
return;
}
if (streamNonExternalAddresses(s).findAny().isEmpty()) {
continue;
}
result.add(s.getName());
count++;
}
}
private void suggestFromProgramBySpace(List<String> result, String got, int max,
AddressSpace space) {
int count = 0;
for (Symbol s : program.getSymbolTable().scanSymbolsByName(got)) {
if (count >= max || !s.getName().startsWith(got)) {
return;
}
if (!streamAddresses(s).anyMatch(a -> a.getAddressSpace() == space)) {
continue;
}
result.add(s.getName());
count++;
}
return result;
}
/**
@ -255,7 +263,18 @@ public final class AssemblyNumericSymbols {
* @return the collection of symbol names
*/
public Collection<String> suggestAny(String got, int max) {
return suggestFrom(got, all.tailSet(got), max, true);
List<String> result = new ArrayList<>();
suggestFrom(result, got, languageLabels.navigableKeySet(), max);
if (program == null) {
return result;
}
suggestFrom(result, got, programEquates.navigableKeySet(), max);
suggestFromProgramAny(result, got, max);
Collections.sort(result);
if (result.size() > max) {
return result.subList(0, max);
}
return result;
}
/**
@ -267,12 +286,17 @@ public final class AssemblyNumericSymbols {
* @return the collection of symbol names
*/
public Collection<String> suggestBySpace(String got, AddressSpace space, int max) {
Map<String, Set<Address>> forSpace = labelsBySpace.get(space);
if (forSpace == null) {
return Set.of();
List<String> result = new ArrayList<>();
suggestFromBySpace(result, got, languageLabels, max, space);
if (program == null) {
return result;
}
// TODO: Should I sort these, perhaps lazily, to speed search?
return suggestFrom(got, forSpace.keySet(), max, false);
suggestFromProgramBySpace(result, got, max, space);
Collections.sort(result);
if (result.size() > max) {
return result.subList(0, max);
}
return result;
}
/**

View file

@ -1572,8 +1572,9 @@ public class ReferenceDBManager implements ReferenceManager, ManagerDB, ErrorHan
* Create a memory reference to the given address to mark it as
* an external entry point.
* @param toAddr the address at which to make an external entry point
* @throws IllegalArgumentException if a non-memory address is specified
*/
public void addExternalEntryPointRef(Address toAddr) {
public void addExternalEntryPointRef(Address toAddr) throws IllegalArgumentException {
if (!toAddr.isMemoryAddress()) {
throw new IllegalArgumentException("Entry point address must be memory address");
}

View file

@ -366,6 +366,16 @@ abstract class SymbolDatabaseAdapter {
*/
abstract RecordIterator getSymbolsByName(String name) throws IOException;
/**
* Scan symbols lexicographically by name starting from the given name
* <p>
* This only includes memory-based stored symbols.
*
* @param startName the starting name to search
* @throws IOException if a database io error occurs
*/
abstract RecordIterator scanSymbolsByName(String startName) throws IOException;
/**
* Get all symbols contained in the given {@link Namespace} that have the given name
* @param name the symbol name

View file

@ -255,6 +255,13 @@ class SymbolDatabaseAdapterV0 extends SymbolDatabaseAdapter {
symbolTable.indexIterator(V0_SYMBOL_NAME_COL, val, val, true));
}
@Override
RecordIterator scanSymbolsByName(String startName) throws IOException {
StringField val = new StringField(startName);
return new V0ConvertedRecordIterator(
symbolTable.indexIterator(V0_SYMBOL_NAME_COL, val, null, true));
}
private class V0ConvertedRecordIterator implements RecordIterator {
private RecordIterator symIter;

View file

@ -254,6 +254,13 @@ class SymbolDatabaseAdapterV1 extends SymbolDatabaseAdapter {
symbolTable.indexIterator(V1_SYMBOL_NAME_COL, field, field, true));
}
@Override
RecordIterator scanSymbolsByName(String startName) throws IOException {
StringField val = new StringField(startName);
return new V1ConvertedRecordIterator(
symbolTable.indexIterator(V1_SYMBOL_NAME_COL, val, null, true));
}
private class V1ConvertedRecordIterator extends ConvertedRecordIterator {
V1ConvertedRecordIterator(RecordIterator originalIterator) {

View file

@ -229,6 +229,13 @@ class SymbolDatabaseAdapterV2 extends SymbolDatabaseAdapter {
return new V2ConvertedRecordIterator(it);
}
@Override
RecordIterator scanSymbolsByName(String startName) throws IOException {
StringField field = new StringField(startName);
RecordIterator it = symbolTable.indexIterator(SYMBOL_NAME_COL, field, null, true);
return new V2ConvertedRecordIterator(it);
}
@Override
Address getMaxSymbolAddress(AddressSpace space) throws IOException {
if (space.isMemorySpace()) {

View file

@ -264,6 +264,12 @@ class SymbolDatabaseAdapterV3 extends SymbolDatabaseAdapter {
return symbolTable.indexIterator(SYMBOL_NAME_COL, field, field, true);
}
@Override
RecordIterator scanSymbolsByName(String startName) throws IOException {
StringField field = new StringField(startName);
return symbolTable.indexIterator(SYMBOL_NAME_COL, field, null, true);
}
@Override
RecordIterator getSymbolsByNameAndNamespace(String name, long id) throws IOException {
// create a range of hash fields for all symbols with this name and namespace id over all

View file

@ -77,6 +77,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
/**
* Creates a new Symbol manager.
*
* @param handle the database handler
* @param addrMap the address map.
* @param openMode the open mode.
@ -125,6 +126,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
/**
* Find previously defined variable storage address
*
* @param storage variable storage
* @return previously defined variable storage address or null if not found
* @throws IOException if there is database exception
@ -136,7 +138,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
@Override
public void setProgram(ProgramDB program) {
this.program = program;
refManager = (ReferenceDBManager) program.getReferenceManager();
refManager = program.getReferenceManager();
namespaceMgr = program.getNamespaceManager();
variableStorageMgr.setProgram(program);
}
@ -177,17 +179,18 @@ public class SymbolManager implements SymbolTable, ManagerDB {
/**
* Check for and upgrade old namespace symbol addresses which included a namespace ID.
* Start at end since Namespace-0 will not result in an OldGenericNamespaceAddress.
* Namespace-0 external symbols do not need to be upgraded since this is effectively
* where all the moved external addresses will be placed.
* The triggering of this upgrade relies on the addition of the VariableManager which
* trigger an upgrade.
* <p>
* Start at end since Namespace-0 will not result in an OldGenericNamespaceAddress. Namespace-0
* external symbols do not need to be upgraded since this is effectively where all the moved
* external addresses will be placed. The triggering of this upgrade relies on the addition of
* the VariableManager which trigger an upgrade.
*
* @param monitor the task monitor
*/
private boolean upgradeOldNamespaceAddresses(TaskMonitor monitor)
throws IOException, CancelledException {
ReferenceDBManager refMgr = (ReferenceDBManager) program.getReferenceManager();
ReferenceDBManager refMgr = program.getReferenceManager();
Address nextExtAddr = getNextExternalSymbolAddress();
@ -236,7 +239,9 @@ public class SymbolManager implements SymbolTable, ManagerDB {
/**
* Upgrade old stack and register variable symbol address to variable addresses.
* <p>
* Also force associated references to be updated to new variable addresses.
*
* @param monitor the task monitor
* @throws IOException if there is database exception
* @throws CancelledException if the operation is cancelled
@ -292,8 +297,10 @@ public class SymbolManager implements SymbolTable, ManagerDB {
/**
* No more sharing the same variable address for multiple variable symbols.
* Must split these up. Only reference to variable addresses should be the
* symbol address - reference refer to physical/stack addresses, and symbolIDs.
* <p>
* Must split these up. Only reference to variable addresses should be the symbol address -
* reference refer to physical/stack addresses, and symbolIDs.
*
* @param monitor the task monitor
* @throws CancelledException if the operation is cancelled
*/
@ -394,6 +401,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
/**
* Add old local symbols
*
* @throws IOException if there is database exception
* @throws CancelledException if the operation is cancelled
*/
@ -442,6 +450,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
/**
* Save off old local symbols whose upgrade needs to be deferred until after function manager
* upgrade has been completed.
*
* @param tmpHandle scratch pad database handle
* @param symbolID local symbol ID
* @param oldAddr old address value from symbol table
@ -628,7 +637,6 @@ public class SymbolManager implements SymbolTable, ManagerDB {
return false;
}
}
//refManager.symbolRemoved(sym);
return sym.delete();
}
finally {
@ -661,6 +669,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
/**
* Removes the symbol directly
*
* @param sym the symbol to remove.
* @return true if the symbol was removed, false otherwise.
*/
@ -1144,6 +1153,21 @@ public class SymbolManager implements SymbolTable, ManagerDB {
return null;
}
@Override
public SymbolIterator scanSymbolsByName(String startName) {
lock.acquire();
try {
return new SymbolNameScanningIterator(startName);
}
catch (IOException e) {
program.dbError(e);
}
finally {
lock.release();
}
return null;
}
@Override
public Symbol getPrimarySymbol(Address addr) {
if (!addr.isMemoryAddress() && !addr.isExternalAddress()) {
@ -1201,6 +1225,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
/**
* Returns the maximum symbol address within the specified address space.
*
* @param space address space
* @return maximum symbol address within space or null if none are found.
*/
@ -1216,6 +1241,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
/**
* Returns the next available external symbol address
*
* @return the address
*/
public Address getNextExternalSymbolAddress() {
@ -1228,14 +1254,18 @@ public class SymbolManager implements SymbolTable, ManagerDB {
}
@Override
public SymbolIterator getPrimarySymbolIterator(Address startAddr, boolean forward) {
public SymbolIterator getPrimarySymbolIterator(Address startAddr, boolean forward)
throws IllegalArgumentException {
if (!startAddr.isMemoryAddress()) {
throw new IllegalArgumentException("Invalid memory address: " + startAddr);
}
return getPrimarySymbolIterator(
program.getAddressFactory().getAddressSet(startAddr, program.getMaxAddress()), forward);
}
@Override
public SymbolIterator getPrimarySymbolIterator(AddressSetView set, boolean forward) {
if (set.isEmpty()) {
if (set != null && set.isEmpty()) {
return SymbolIterator.EMPTY_ITERATOR;
}
try {
@ -1250,7 +1280,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
@Override
public SymbolIterator getSymbols(AddressSetView set, SymbolType type, boolean forward) {
if (set.isEmpty()) {
if (set != null && set.isEmpty()) {
return SymbolIterator.EMPTY_ITERATOR;
}
Query query =
@ -1264,7 +1294,11 @@ public class SymbolManager implements SymbolTable, ManagerDB {
}
@Override
public SymbolIterator getSymbolIterator(Address startAddr, boolean forward) {
public SymbolIterator getSymbolIterator(Address startAddr, boolean forward)
throws IllegalArgumentException {
if (!startAddr.isMemoryAddress()) {
throw new IllegalArgumentException("Invalid memory address: " + startAddr);
}
RecordIterator it;
try {
it = adapter.getSymbolsByAddress(startAddr, forward);
@ -1315,7 +1349,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
}
@Override
public void addExternalEntryPoint(Address addr) {
public void addExternalEntryPoint(Address addr) throws IllegalArgumentException {
refManager.addExternalEntryPointRef(addr);
}
@ -1394,10 +1428,12 @@ public class SymbolManager implements SymbolTable, ManagerDB {
}
/**
* Move symbol. Only symbol address is changed.
* References must be moved separately.
* @param oldAddr the old symbol address
* @param newAddr the new symbol address
* Move symbol.
* <p>
* Only symbol address is changed. References must be moved separately.
*
* @param oldAddr the old symbol memory address
* @param newAddr the new symbol memory address
*/
public void moveSymbolsAt(Address oldAddr, Address newAddr) {
lock.acquire();
@ -1422,6 +1458,9 @@ public class SymbolManager implements SymbolTable, ManagerDB {
// Unique dynamic symbol ID produced from a dynamic symbol address map which has a
// high-order bit set to avoid potential conflict with stored symbol ID's which are
// assigned starting at 0.
if (!addr.isMemoryAddress()) {
throw new IllegalArgumentException("Invalid memory address: " + addr);
}
return dynamicSymbolAddressMap.getKey(addr);
}
@ -1450,16 +1489,17 @@ public class SymbolManager implements SymbolTable, ManagerDB {
}
FunctionManagerDB getFunctionManager() {
return (FunctionManagerDB) program.getFunctionManager();
return program.getFunctionManager();
}
ExternalManagerDB getExternalManager() {
return (ExternalManagerDB) program.getExternalManager();
return program.getExternalManager();
}
/**
* Called by the NamespaceManager when a namespace is removed; remove all symbols that have the
* given namespace ID.
*
* @param namespaceID ID of namespace being removed
*/
public void namespaceRemoved(long namespaceID) {
@ -1849,11 +1889,11 @@ public class SymbolManager implements SymbolTable, ManagerDB {
}
}
private class SymbolNameRecordIterator implements SymbolIterator {
private abstract class AbstractSymbolNameRecordIterator implements SymbolIterator {
private RecordIterator it;
SymbolNameRecordIterator(String name) throws IOException {
this.it = adapter.getSymbolsByName(name);
AbstractSymbolNameRecordIterator(RecordIterator it) {
this.it = it;
}
@Override
@ -1891,6 +1931,18 @@ public class SymbolManager implements SymbolTable, ManagerDB {
}
}
private class SymbolNameRecordIterator extends AbstractSymbolNameRecordIterator {
SymbolNameRecordIterator(String name) throws IOException {
super(adapter.getSymbolsByName(name));
}
}
private class SymbolNameScanningIterator extends AbstractSymbolNameRecordIterator {
public SymbolNameScanningIterator(String startName) throws IOException {
super(adapter.scanSymbolsByName(startName));
}
}
private class ExternalSymbolNameRecordIterator implements SymbolIterator {
private RecordIterator it;
@ -2302,6 +2354,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
/**
* Checks to make sure there is a single valid primary symbol at each address
*
* @param set the set of addresses that may have to be fixed up
*/
private void fixupPrimarySymbols(Set<Address> set) {
@ -2342,9 +2395,12 @@ public class SymbolManager implements SymbolTable, ManagerDB {
}
/**
* Checks if the givens symbols from the same address have exactly one primary symbol amongst them
* Checks if the givens symbols from the same address have exactly one primary symbol amongst
* them
*
* @param symbols the array of symbols at a an address
* @return true if there is exactly one primary symbol at the address (also true if no symbols at address)
* @return true if there is exactly one primary symbol at the address (also true if no symbols
* at address)
*/
private boolean hasValidPrimary(Symbol[] symbols) {
if (symbols.length == 0) {
@ -2496,8 +2552,11 @@ public class SymbolManager implements SymbolTable, ManagerDB {
}
/**
* Creates variable symbols. Note this is not a method defined in the Symbol Table interface.
* It is intended to be used by Ghidra program internals.
* Creates variable symbols.
* <p>
* Note this is not a method defined in the Symbol Table interface. It is intended to be used by
* Ghidra program internals.
*
* @param name the name of the variable
* @param function the function that contains the variable.
* @param type the type of the variable (can only be PARAMETER or LOCAL_VAR)
@ -2649,6 +2708,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
/**
* Create a Library symbol with the specified name and optional pathname
*
* @param name library name
* @param pathname project file path (may be null)
* @param source symbol source
@ -2664,6 +2724,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
/**
* Create a Class symbol with the specified name and parent
*
* @param name class name
* @param parent parent namespace (may be null for global namespace)
* @param source symbol source
@ -2680,6 +2741,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
/**
* Create a simple Namespace symbol with the specified name and parent
*
* @param name class name
* @param parent parent namespace (may be null for global namespace)
* @param source symbol source
@ -2730,11 +2792,14 @@ public class SymbolManager implements SymbolTable, ManagerDB {
}
/**
* Internal method for creating label symbols. If identical memory symbol already exists
* it will be returned.
* Internal method for creating label symbols.
* <p>
* If identical memory symbol already exists it will be returned.
*
* @param addr the address for the new symbol (memory or external)
* @param name the name of the new symbol
* @param namespace the namespace for the new symbol (null may be specified for global namespace)
* @param namespace the namespace for the new symbol (null may be specified for global
* namespace)
* @param source the SourceType of the new symbol
* @param stringData special use depending on the symbol type and whether or not it is external
* @return the new symbol
@ -2771,14 +2836,14 @@ public class SymbolManager implements SymbolTable, ManagerDB {
makePrimary = (primary == null);
}
else if (addr.isExternalAddress()) {
// only one symbol per external address is allowed
// TODO: remove support for external symbol creation from this method (see GP-3045)
Symbol primary = getPrimarySymbol(addr);
if (primary != null) {
if (primary != null) { // only one symbol per external address is allowed
throw new IllegalArgumentException("external address already used");
}
}
else {
throw new IllegalArgumentException("bad label address");
throw new IllegalArgumentException("Invalid memory address: " + addr);
}
return doCreateSymbol(name, addr, namespace, SymbolType.LABEL, stringData, null, null,
@ -2794,7 +2859,8 @@ public class SymbolManager implements SymbolTable, ManagerDB {
*
* @param addr the address for the new symbol
* @param name the name of the new symbol
* @param namespace the namespace for the new symbol (null may be specified for global namespace)
* @param namespace the namespace for the new symbol (null may be specified for global
* namespace)
* @param source the SourceType of the new symbol
* @param stringData special use depending on the symbol type and whether or not it is external.
* @return the new symbol
@ -2866,9 +2932,11 @@ public class SymbolManager implements SymbolTable, ManagerDB {
}
/**
* Finds the appropriate symbol to promote when function is created. And by promote, we really
* mean find the symbol that needs to be deleted before creating the function symbol. If the
* found symbol is not dynamic, the function symbol will assume its name and namespace.
* Finds the appropriate symbol to promote when function is created.
* <p>
* And by promote, we really mean find the symbol that needs to be deleted before creating the
* function symbol. If the found symbol is not dynamic, the function symbol will assume its name
* and namespace.
*/
private Symbol findSymbolToPromote(Symbol matching, Symbol primary, SourceType source) {
// if the function is default, then the primary will be promoted

View file

@ -17,6 +17,7 @@ package ghidra.program.model.symbol;
import java.util.*;
import java.util.function.Consumer;
import java.util.stream.Stream;
import ghidra.program.model.address.*;
import ghidra.program.model.data.*;
@ -85,7 +86,7 @@ public class SymbolUtilities {
DEFAULT_DATA_PREFIX, DEFAULT_SYMBOL_PREFIX, DEFAULT_SUBROUTINE_PREFIX,
DEFAULT_UNKNOWN_PREFIX, DEFAULT_EXTERNAL_ENTRY_PREFIX, DEFAULT_FUNCTION_PREFIX };
private static List<String> DYNAMIC_DATA_TYPE_PREFIXES = getDynamicDataTypePrefixes();
private final static List<String> DYNAMIC_DATA_TYPE_PREFIXES = getDynamicDataTypePrefixes();
/**
* Any dynamic label will have an address with this minimum length or longer
@ -574,7 +575,7 @@ public class SymbolUtilities {
*/
public static Address parseDynamicName(AddressFactory factory, String name) {
// assume dynamic names will naver start with an underscore
// assume dynamic names will never start with an underscore
if (name.startsWith(UNDERSCORE)) {
return null;
}
@ -591,7 +592,7 @@ public class SymbolUtilities {
space = factory.getDefaultAddressSpace();
}
// Only consider address values which meet the meet the minimum padding behavior
// Only consider address values which meet the minimum padding behavior
if (addressOffsetString.length() < MIN_LABEL_ADDRESS_DIGITS) {
return null;
}

View file

@ -172,6 +172,11 @@ public class StubSymbolTable implements SymbolTable {
throw new UnsupportedOperationException();
}
@Override
public SymbolIterator scanSymbolsByName(String startName) {
throw new UnsupportedOperationException();
}
@Override
public int getNumSymbols() {
throw new UnsupportedOperationException();