mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 19:42:36 +02:00
Merge remote-tracking branch
'origin/GP-3015_Dan_symbolsByNameAssemblerFix--REBASED-1' (Closes #2630)
This commit is contained in:
commit
aa7a93f0a3
17 changed files with 801 additions and 466 deletions
|
@ -380,6 +380,11 @@ public class DBTraceProgramViewSymbolTable implements SymbolTable {
|
|||
}));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SymbolIterator scanSymbolsByName(String startName) {
|
||||
return new SymbolIteratorAdapter(symbolManager.allSymbols().scanByName(startName));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumSymbols() {
|
||||
return symbolManager.allSymbols().size(true);
|
||||
|
|
|
@ -88,6 +88,10 @@ public abstract class AbstractDBTraceSymbolSingleTypeView<T extends AbstractDBTr
|
|||
return Collections2.filter(view, s -> predicate.test(s.name));
|
||||
}
|
||||
|
||||
public Iterator<? extends T> scanByName(String startName) {
|
||||
return symbolsByName.tail(startName, true).values().iterator();
|
||||
}
|
||||
|
||||
public T getByKey(long key) {
|
||||
return store.getObjectAt(key);
|
||||
}
|
||||
|
|
|
@ -15,13 +15,14 @@
|
|||
*/
|
||||
package ghidra.trace.database.symbol;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.google.common.collect.Collections2;
|
||||
|
||||
import generic.CatenatedCollection;
|
||||
import ghidra.trace.model.symbol.*;
|
||||
import ghidra.util.MergeSortingIterator;
|
||||
|
||||
public class DBTraceSymbolMultipleTypesView<T extends AbstractDBTraceSymbol>
|
||||
implements TraceSymbolView<T> {
|
||||
|
@ -73,4 +74,11 @@ public class DBTraceSymbolMultipleTypesView<T extends AbstractDBTraceSymbol>
|
|||
return new CatenatedCollection<>(
|
||||
Collections2.transform(parts, p -> p.getWithMatchingName(glob, caseSensitive)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<? extends T> scanByName(String startName) {
|
||||
List<Iterator<? extends T>> iterators =
|
||||
parts.stream().map(p -> p.scanByName(startName)).collect(Collectors.toList());
|
||||
return new MergeSortingIterator<>(iterators, Comparator.comparing(s -> s.getName()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
package ghidra.trace.model.symbol;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
|
||||
public interface TraceSymbolView<T extends TraceSymbol> {
|
||||
|
||||
|
@ -55,4 +56,6 @@ public interface TraceSymbolView<T extends TraceSymbol> {
|
|||
* @return the collection of matching symbols
|
||||
*/
|
||||
Collection<? extends T> getWithMatchingName(String glob, boolean caseSensitive);
|
||||
|
||||
Iterator<? extends T> scanByName(String startName);
|
||||
}
|
||||
|
|
|
@ -722,7 +722,7 @@ public class SymbolTablePlugin extends Plugin implements DomainObjectListener {
|
|||
}
|
||||
}
|
||||
else if (toAddr.isMemoryAddress() && symProvider.isShowingDynamicSymbols()) {
|
||||
long dynamicSymbolId = symbolTable.getDynamicSymbolID(reference.getToAddress());
|
||||
long dynamicSymbolId = symbolTable.getDynamicSymbolID(toAddr);
|
||||
symProvider.symbolRemoved(dynamicSymbolId);
|
||||
refProvider.symbolRemoved(dynamicSymbolId);
|
||||
}
|
||||
|
|
|
@ -1265,6 +1265,7 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
createExternalFunction("7");
|
||||
createExternalLabel("8");
|
||||
|
||||
// test restricted address range
|
||||
AddressSet set = new AddressSet(addr(0), addr(50));
|
||||
set.addRange(addr(300), addr(350));
|
||||
set.addRange(addr(500), addr(1000));
|
||||
|
@ -1275,22 +1276,48 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
// External space before memory space
|
||||
Symbol s = it.next();
|
||||
assertNotNull(s);
|
||||
assertEquals("7", s.getName());
|
||||
assertEquals("Test::7", s.getName(true));
|
||||
assertEquals(extAddr(1), s.getAddress());
|
||||
s = it.next();
|
||||
assertNotNull(s);
|
||||
assertEquals("8", s.getName());
|
||||
assertEquals("Test::8", s.getName(true));
|
||||
assertEquals(extAddr(2), s.getAddress());
|
||||
|
||||
s = it.next();
|
||||
assertNotNull(s);
|
||||
assertEquals("3", s.getName(true));
|
||||
assertEquals(addr(300), s.getAddress());
|
||||
s = it.next();
|
||||
assertNotNull(s);
|
||||
assertEquals("5", s.getName(true));
|
||||
assertEquals(addr(500), s.getAddress());
|
||||
|
||||
assertTrue(!it.hasNext());
|
||||
assertNull(it.next());
|
||||
|
||||
// test all memory/external
|
||||
it = st.getPrimarySymbolIterator((AddressSetView) null, true);
|
||||
|
||||
assertTrue(it.hasNext());
|
||||
s = it.next();
|
||||
assertNotNull(s);
|
||||
assertEquals("Test::7", s.getName(true));
|
||||
|
||||
assertTrue(it.hasNext());
|
||||
s = it.next();
|
||||
assertNotNull(s);
|
||||
assertEquals("Test::8", s.getName(true));
|
||||
|
||||
for (int i = 1; i <= 6; i++) {
|
||||
assertTrue(it.hasNext());
|
||||
s = it.next();
|
||||
assertNotNull(s);
|
||||
assertEquals(Integer.toString(i), s.getName(true));
|
||||
}
|
||||
|
||||
assertTrue(!it.hasNext());
|
||||
assertNull(it.next());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -1433,12 +1460,31 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
createLabel(addr(100), "1");
|
||||
createLabel(addr(200), "2");
|
||||
createLabel(addr(300), "3");
|
||||
Function extFunc = createExternalFunction("X");
|
||||
createExternalLabel("Y");
|
||||
|
||||
Function f1 = createFunction("A", addr(150));
|
||||
Function f2 = createFunction("B", addr(250));
|
||||
|
||||
SymbolIterator it =
|
||||
st.getSymbols(new AddressSet(addr(0), addr(5000)), SymbolType.FUNCTION, true);
|
||||
// test over constrained address set
|
||||
AddressSet set = new AddressSet(addr(0), addr(200));
|
||||
set.addRange(AddressSpace.EXTERNAL_SPACE.getMinAddress(),
|
||||
AddressSpace.EXTERNAL_SPACE.getMaxAddress());
|
||||
|
||||
SymbolIterator it = st.getSymbols(set, SymbolType.FUNCTION, true);
|
||||
|
||||
assertTrue(it.hasNext());
|
||||
assertEquals(extFunc.getSymbol(), it.next());
|
||||
|
||||
assertTrue(it.hasNext());
|
||||
assertEquals(f1.getSymbol(), it.next());
|
||||
|
||||
assertFalse(it.hasNext());
|
||||
|
||||
it = st.getSymbols(null, SymbolType.FUNCTION, true);
|
||||
|
||||
assertTrue(it.hasNext());
|
||||
assertEquals(extFunc.getSymbol(), it.next());
|
||||
|
||||
assertTrue(it.hasNext());
|
||||
assertEquals(f1.getSymbol(), it.next());
|
||||
|
@ -2440,11 +2486,11 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
.getSymbol();
|
||||
}
|
||||
|
||||
private Symbol createExternalFunction(String name)
|
||||
private Function createExternalFunction(String name)
|
||||
throws InvalidInputException, DuplicateNameException {
|
||||
ExternalManager externalManager = program.getExternalManager();
|
||||
return externalManager.addExtFunction("Test", name, null, SourceType.USER_DEFINED)
|
||||
.getSymbol();
|
||||
.getFunction();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
private static Stream<Address> streamAddresses(Symbol sym) {
|
||||
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());
|
||||
return Stream.of(sym.getAddress());
|
||||
}
|
||||
if (symbolType == SymbolType.FUNCTION) {
|
||||
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);
|
||||
return thunks == null ? Stream.of(sym.getAddress())
|
||||
: Stream.concat(Stream.of(sym.getAddress()), Stream.of(thunks));
|
||||
}
|
||||
return Stream.of();
|
||||
}
|
||||
}
|
||||
}
|
||||
// Ignore other symbol types
|
||||
}
|
||||
|
||||
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;
|
||||
for (String k : keys.tailSet(got)) {
|
||||
if (count >= max || !k.startsWith(got)) {
|
||||
return;
|
||||
}
|
||||
if (label.startsWith(got)) {
|
||||
result.add(label);
|
||||
result.add(k);
|
||||
count++;
|
||||
}
|
||||
else if (sorted) {
|
||||
break;
|
||||
}
|
||||
|
||||
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++;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
||||
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++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue