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
|
@Override
|
||||||
public int getNumSymbols() {
|
public int getNumSymbols() {
|
||||||
return symbolManager.allSymbols().size(true);
|
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));
|
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) {
|
public T getByKey(long key) {
|
||||||
return store.getObjectAt(key);
|
return store.getObjectAt(key);
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,13 +15,14 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.trace.database.symbol;
|
package ghidra.trace.database.symbol;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.*;
|
||||||
import java.util.Collection;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import com.google.common.collect.Collections2;
|
import com.google.common.collect.Collections2;
|
||||||
|
|
||||||
import generic.CatenatedCollection;
|
import generic.CatenatedCollection;
|
||||||
import ghidra.trace.model.symbol.*;
|
import ghidra.trace.model.symbol.*;
|
||||||
|
import ghidra.util.MergeSortingIterator;
|
||||||
|
|
||||||
public class DBTraceSymbolMultipleTypesView<T extends AbstractDBTraceSymbol>
|
public class DBTraceSymbolMultipleTypesView<T extends AbstractDBTraceSymbol>
|
||||||
implements TraceSymbolView<T> {
|
implements TraceSymbolView<T> {
|
||||||
|
@ -73,4 +74,11 @@ public class DBTraceSymbolMultipleTypesView<T extends AbstractDBTraceSymbol>
|
||||||
return new CatenatedCollection<>(
|
return new CatenatedCollection<>(
|
||||||
Collections2.transform(parts, p -> p.getWithMatchingName(glob, caseSensitive)));
|
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;
|
package ghidra.trace.model.symbol;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
public interface TraceSymbolView<T extends TraceSymbol> {
|
public interface TraceSymbolView<T extends TraceSymbol> {
|
||||||
|
|
||||||
|
@ -55,4 +56,6 @@ public interface TraceSymbolView<T extends TraceSymbol> {
|
||||||
* @return the collection of matching symbols
|
* @return the collection of matching symbols
|
||||||
*/
|
*/
|
||||||
Collection<? extends T> getWithMatchingName(String glob, boolean caseSensitive);
|
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()) {
|
else if (toAddr.isMemoryAddress() && symProvider.isShowingDynamicSymbols()) {
|
||||||
long dynamicSymbolId = symbolTable.getDynamicSymbolID(reference.getToAddress());
|
long dynamicSymbolId = symbolTable.getDynamicSymbolID(toAddr);
|
||||||
symProvider.symbolRemoved(dynamicSymbolId);
|
symProvider.symbolRemoved(dynamicSymbolId);
|
||||||
refProvider.symbolRemoved(dynamicSymbolId);
|
refProvider.symbolRemoved(dynamicSymbolId);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1265,6 +1265,7 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
createExternalFunction("7");
|
createExternalFunction("7");
|
||||||
createExternalLabel("8");
|
createExternalLabel("8");
|
||||||
|
|
||||||
|
// test restricted address range
|
||||||
AddressSet set = new AddressSet(addr(0), addr(50));
|
AddressSet set = new AddressSet(addr(0), addr(50));
|
||||||
set.addRange(addr(300), addr(350));
|
set.addRange(addr(300), addr(350));
|
||||||
set.addRange(addr(500), addr(1000));
|
set.addRange(addr(500), addr(1000));
|
||||||
|
@ -1275,22 +1276,48 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
// External space before memory space
|
// External space before memory space
|
||||||
Symbol s = it.next();
|
Symbol s = it.next();
|
||||||
assertNotNull(s);
|
assertNotNull(s);
|
||||||
assertEquals("7", s.getName());
|
assertEquals("Test::7", s.getName(true));
|
||||||
assertEquals(extAddr(1), s.getAddress());
|
assertEquals(extAddr(1), s.getAddress());
|
||||||
s = it.next();
|
s = it.next();
|
||||||
assertNotNull(s);
|
assertNotNull(s);
|
||||||
assertEquals("8", s.getName());
|
assertEquals("Test::8", s.getName(true));
|
||||||
assertEquals(extAddr(2), s.getAddress());
|
assertEquals(extAddr(2), s.getAddress());
|
||||||
|
|
||||||
s = it.next();
|
s = it.next();
|
||||||
assertNotNull(s);
|
assertNotNull(s);
|
||||||
|
assertEquals("3", s.getName(true));
|
||||||
assertEquals(addr(300), s.getAddress());
|
assertEquals(addr(300), s.getAddress());
|
||||||
s = it.next();
|
s = it.next();
|
||||||
assertNotNull(s);
|
assertNotNull(s);
|
||||||
|
assertEquals("5", s.getName(true));
|
||||||
assertEquals(addr(500), s.getAddress());
|
assertEquals(addr(500), s.getAddress());
|
||||||
|
|
||||||
assertTrue(!it.hasNext());
|
assertTrue(!it.hasNext());
|
||||||
assertNull(it.next());
|
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
|
@Test
|
||||||
|
@ -1433,12 +1460,31 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
createLabel(addr(100), "1");
|
createLabel(addr(100), "1");
|
||||||
createLabel(addr(200), "2");
|
createLabel(addr(200), "2");
|
||||||
createLabel(addr(300), "3");
|
createLabel(addr(300), "3");
|
||||||
|
Function extFunc = createExternalFunction("X");
|
||||||
|
createExternalLabel("Y");
|
||||||
|
|
||||||
Function f1 = createFunction("A", addr(150));
|
Function f1 = createFunction("A", addr(150));
|
||||||
Function f2 = createFunction("B", addr(250));
|
Function f2 = createFunction("B", addr(250));
|
||||||
|
|
||||||
SymbolIterator it =
|
// test over constrained address set
|
||||||
st.getSymbols(new AddressSet(addr(0), addr(5000)), SymbolType.FUNCTION, true);
|
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());
|
assertTrue(it.hasNext());
|
||||||
assertEquals(f1.getSymbol(), it.next());
|
assertEquals(f1.getSymbol(), it.next());
|
||||||
|
@ -2440,11 +2486,11 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
.getSymbol();
|
.getSymbol();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Symbol createExternalFunction(String name)
|
private Function createExternalFunction(String name)
|
||||||
throws InvalidInputException, DuplicateNameException {
|
throws InvalidInputException, DuplicateNameException {
|
||||||
ExternalManager externalManager = program.getExternalManager();
|
ExternalManager externalManager = program.getExternalManager();
|
||||||
return externalManager.addExtFunction("Test", name, null, SourceType.USER_DEFINED)
|
return externalManager.addExtFunction("Test", name, null, SourceType.USER_DEFINED)
|
||||||
.getSymbol();
|
.getFunction();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,9 @@
|
||||||
package ghidra.app.plugin.assembler.sleigh.symbol;
|
package ghidra.app.plugin.assembler.sleigh.symbol;
|
||||||
|
|
||||||
import java.util.*;
|
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.Address;
|
||||||
import ghidra.program.model.address.AddressSpace;
|
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.
|
* A context to hold various symbols offered to the assembler, usable where numbers are expected.
|
||||||
*/
|
*/
|
||||||
public final class AssemblyNumericSymbols {
|
public final class AssemblyNumericSymbols {
|
||||||
public static final AssemblyNumericSymbols EMPTY =
|
public static final AssemblyNumericSymbols EMPTY = new AssemblyNumericSymbols();
|
||||||
new AssemblyNumericSymbols(Map.of(), Map.of(), Map.of());
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Collect labels derived from memory-mapped registers in a language
|
* Collect labels derived from memory-mapped registers in a language
|
||||||
|
@ -42,7 +43,8 @@ public final class AssemblyNumericSymbols {
|
||||||
* @param labels the destination map
|
* @param labels the destination map
|
||||||
* @param language the language
|
* @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()) {
|
for (Register reg : language.getRegisters()) {
|
||||||
// TODO/HACK: There ought to be a better mechanism describing suitable symbolic
|
// TODO/HACK: There ought to be a better mechanism describing suitable symbolic
|
||||||
// substitutions for a given operand.
|
// substitutions for a given operand.
|
||||||
|
@ -50,42 +52,25 @@ public final class AssemblyNumericSymbols {
|
||||||
labels.computeIfAbsent(reg.getName(), n -> new HashSet<>()).add(reg.getAddress());
|
labels.computeIfAbsent(reg.getName(), n -> new HashSet<>()).add(reg.getAddress());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return labels;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private static Stream<Address> streamAddresses(Symbol sym) {
|
||||||
* Collect labels from the program's database
|
SymbolType symbolType = sym.getSymbolType();
|
||||||
*
|
if (symbolType == SymbolType.LABEL) {
|
||||||
* @param labels the destination map
|
return Stream.of(sym.getAddress());
|
||||||
* @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
|
|
||||||
}
|
}
|
||||||
|
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 equates the destination map
|
||||||
* @param programthe source program
|
* @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();
|
final Iterator<Equate> it = program.getEquateTable().getEquates();
|
||||||
while (it.hasNext()) {
|
while (it.hasNext()) {
|
||||||
Equate eq = it.next();
|
Equate eq = it.next();
|
||||||
// Thought is: If that's what the user sees, then that's what the user will type!
|
// 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());
|
equates.computeIfAbsent(eq.getDisplayName(), n -> new HashSet<>()).add(eq.getValue());
|
||||||
}
|
}
|
||||||
|
return equates;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -110,84 +97,60 @@ public final class AssemblyNumericSymbols {
|
||||||
* @return the symbols
|
* @return the symbols
|
||||||
*/
|
*/
|
||||||
public static AssemblyNumericSymbols fromLanguage(Language language) {
|
public static AssemblyNumericSymbols fromLanguage(Language language) {
|
||||||
Map<String, Set<Address>> labels = new HashMap<>();
|
return new AssemblyNumericSymbols(language);
|
||||||
collectLanguageLabels(labels, language);
|
|
||||||
return forMaps(Map.of(), labels);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get symbols from a program (and its 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
|
* @param program the program
|
||||||
* @return the symbols
|
* @return the symbols
|
||||||
*/
|
*/
|
||||||
public static AssemblyNumericSymbols fromProgram(Program program) {
|
public static AssemblyNumericSymbols fromProgram(Program program) {
|
||||||
Map<String, Set<Long>> equates = new HashMap<>();
|
return new AssemblyNumericSymbols(program);
|
||||||
Map<String, Set<Address>> labels = new HashMap<>();
|
|
||||||
collectLanguageLabels(labels, program.getLanguage());
|
|
||||||
collectProgramLabels(labels, program);
|
|
||||||
collectProgramEquates(equates, program);
|
|
||||||
return forMaps(equates, labels);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public final NavigableMap<String, Set<Long>> programEquates;
|
||||||
* Get symbols for the given equate and label maps
|
public final NavigableMap<String, Set<Address>> languageLabels;
|
||||||
*
|
private final Program program;
|
||||||
* @param equates the equates
|
|
||||||
* @param labels the labels
|
private AssemblyNumericSymbols() {
|
||||||
* @return the symbols
|
this.program = null;
|
||||||
*/
|
this.programEquates = new TreeMap<>();
|
||||||
public static AssemblyNumericSymbols forMaps(Map<String, Set<Long>> equates,
|
this.languageLabels = new TreeMap<>();
|
||||||
Map<String, Set<Address>> labels) {
|
|
||||||
return new AssemblyNumericSymbols(Map.copyOf(equates), Map.copyOf(labels),
|
|
||||||
groupBySpace(labels));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Map<AddressSpace, Map<String, Set<Address>>> groupBySpace(
|
private AssemblyNumericSymbols(Language language) {
|
||||||
Map<String, Set<Address>> labels) {
|
this.program = null;
|
||||||
Map<AddressSpace, Map<String, Set<Address>>> result = new HashMap<>();
|
this.programEquates = new TreeMap<>();
|
||||||
for (Map.Entry<String, Set<Address>> entry : labels.entrySet()) {
|
this.languageLabels = collectLanguageLabels(language);
|
||||||
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 final NavigableSet<String> all = new TreeSet<>();
|
private AssemblyNumericSymbols(Program program) {
|
||||||
public final Map<String, Set<Long>> equates;
|
this.program = program;
|
||||||
public final Map<String, Set<Address>> labels;
|
this.programEquates = collectProgramEquates(program);
|
||||||
public final Map<AddressSpace, Map<String, Set<Address>>> labelsBySpace;
|
this.languageLabels = collectLanguageLabels(program.getLanguage());
|
||||||
|
|
||||||
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());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Choose any symbol with the given name
|
* Choose any symbol with the given name
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* This will check equates first, then labels. If an equate is found, its value is returned. If
|
* This will order equates first, then program labels, then language labels. For addresses, the
|
||||||
* a label is found, its addressable word offset is returned.
|
* value is its addressable word offset.
|
||||||
*
|
*
|
||||||
* @param name the name
|
* @param name the name
|
||||||
* @return the value, or null
|
* @return the value, or null
|
||||||
*/
|
*/
|
||||||
public Set<Long> chooseAll(String name) {
|
public Set<Long> chooseAll(String name) {
|
||||||
Set<Long> result = new TreeSet<>();
|
Set<Long> result = new TreeSet<>();
|
||||||
result.addAll(equates.getOrDefault(name, Set.of()));
|
result.addAll(programEquates.getOrDefault(name, Set.of()));
|
||||||
for (Address address : labels.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());
|
result.add(address.getAddressableWordOffset());
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
@ -201,11 +164,20 @@ public final class AssemblyNumericSymbols {
|
||||||
* @return the addressable word offset of the found label, or null
|
* @return the addressable word offset of the found label, or null
|
||||||
*/
|
*/
|
||||||
public Set<Long> chooseBySpace(String name, AddressSpace space) {
|
public Set<Long> chooseBySpace(String name, AddressSpace space) {
|
||||||
return labelsBySpace.getOrDefault(space, Map.of())
|
Set<Long> result = new TreeSet<>();
|
||||||
.getOrDefault(name, Set.of())
|
if (program != null) {
|
||||||
.stream()
|
StreamSupport.stream(program.getSymbolTable().getSymbols(name).spliterator(), false)
|
||||||
.map(a -> a.getAddressableWordOffset())
|
.flatMap(sym -> streamAddresses(sym))
|
||||||
.collect(Collectors.toSet());
|
.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);
|
return chooseBySpace(name, space);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Collection<String> suggestFrom(String got, Collection<String> keys, int max,
|
private void suggestFrom(List<String> result, String got, NavigableSet<String> keys, int max) {
|
||||||
boolean sorted) {
|
|
||||||
Set<String> result = new HashSet<>();
|
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for (String label : keys) {
|
for (String k : keys.tailSet(got)) {
|
||||||
if (count >= max) {
|
if (count >= max || !k.startsWith(got)) {
|
||||||
break;
|
return;
|
||||||
}
|
|
||||||
if (label.startsWith(got)) {
|
|
||||||
result.add(label);
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
else if (sorted) {
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
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
|
* @return the collection of symbol names
|
||||||
*/
|
*/
|
||||||
public Collection<String> suggestAny(String got, int max) {
|
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
|
* @return the collection of symbol names
|
||||||
*/
|
*/
|
||||||
public Collection<String> suggestBySpace(String got, AddressSpace space, int max) {
|
public Collection<String> suggestBySpace(String got, AddressSpace space, int max) {
|
||||||
Map<String, Set<Address>> forSpace = labelsBySpace.get(space);
|
List<String> result = new ArrayList<>();
|
||||||
if (forSpace == null) {
|
suggestFromBySpace(result, got, languageLabels, max, space);
|
||||||
return Set.of();
|
if (program == null) {
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
// TODO: Should I sort these, perhaps lazily, to speed search?
|
suggestFromProgramBySpace(result, got, max, space);
|
||||||
return suggestFrom(got, forSpace.keySet(), max, false);
|
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
|
* Create a memory reference to the given address to mark it as
|
||||||
* an external entry point.
|
* an external entry point.
|
||||||
* @param toAddr the address at which to make 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()) {
|
if (!toAddr.isMemoryAddress()) {
|
||||||
throw new IllegalArgumentException("Entry point address must be memory address");
|
throw new IllegalArgumentException("Entry point address must be memory address");
|
||||||
}
|
}
|
||||||
|
|
|
@ -366,6 +366,16 @@ abstract class SymbolDatabaseAdapter {
|
||||||
*/
|
*/
|
||||||
abstract RecordIterator getSymbolsByName(String name) throws IOException;
|
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
|
* Get all symbols contained in the given {@link Namespace} that have the given name
|
||||||
* @param name the symbol name
|
* @param name the symbol name
|
||||||
|
|
|
@ -255,6 +255,13 @@ class SymbolDatabaseAdapterV0 extends SymbolDatabaseAdapter {
|
||||||
symbolTable.indexIterator(V0_SYMBOL_NAME_COL, val, val, true));
|
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 class V0ConvertedRecordIterator implements RecordIterator {
|
||||||
|
|
||||||
private RecordIterator symIter;
|
private RecordIterator symIter;
|
||||||
|
|
|
@ -254,6 +254,13 @@ class SymbolDatabaseAdapterV1 extends SymbolDatabaseAdapter {
|
||||||
symbolTable.indexIterator(V1_SYMBOL_NAME_COL, field, field, true));
|
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 {
|
private class V1ConvertedRecordIterator extends ConvertedRecordIterator {
|
||||||
|
|
||||||
V1ConvertedRecordIterator(RecordIterator originalIterator) {
|
V1ConvertedRecordIterator(RecordIterator originalIterator) {
|
||||||
|
|
|
@ -229,6 +229,13 @@ class SymbolDatabaseAdapterV2 extends SymbolDatabaseAdapter {
|
||||||
return new V2ConvertedRecordIterator(it);
|
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
|
@Override
|
||||||
Address getMaxSymbolAddress(AddressSpace space) throws IOException {
|
Address getMaxSymbolAddress(AddressSpace space) throws IOException {
|
||||||
if (space.isMemorySpace()) {
|
if (space.isMemorySpace()) {
|
||||||
|
|
|
@ -264,6 +264,12 @@ class SymbolDatabaseAdapterV3 extends SymbolDatabaseAdapter {
|
||||||
return symbolTable.indexIterator(SYMBOL_NAME_COL, field, field, true);
|
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
|
@Override
|
||||||
RecordIterator getSymbolsByNameAndNamespace(String name, long id) throws IOException {
|
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
|
// 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.
|
* Creates a new Symbol manager.
|
||||||
|
*
|
||||||
* @param handle the database handler
|
* @param handle the database handler
|
||||||
* @param addrMap the address map.
|
* @param addrMap the address map.
|
||||||
* @param openMode the open mode.
|
* @param openMode the open mode.
|
||||||
|
@ -125,6 +126,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find previously defined variable storage address
|
* Find previously defined variable storage address
|
||||||
|
*
|
||||||
* @param storage variable storage
|
* @param storage variable storage
|
||||||
* @return previously defined variable storage address or null if not found
|
* @return previously defined variable storage address or null if not found
|
||||||
* @throws IOException if there is database exception
|
* @throws IOException if there is database exception
|
||||||
|
@ -136,7 +138,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
||||||
@Override
|
@Override
|
||||||
public void setProgram(ProgramDB program) {
|
public void setProgram(ProgramDB program) {
|
||||||
this.program = program;
|
this.program = program;
|
||||||
refManager = (ReferenceDBManager) program.getReferenceManager();
|
refManager = program.getReferenceManager();
|
||||||
namespaceMgr = program.getNamespaceManager();
|
namespaceMgr = program.getNamespaceManager();
|
||||||
variableStorageMgr.setProgram(program);
|
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.
|
* 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.
|
* <p>
|
||||||
* Namespace-0 external symbols do not need to be upgraded since this is effectively
|
* Start at end since Namespace-0 will not result in an OldGenericNamespaceAddress. Namespace-0
|
||||||
* where all the moved external addresses will be placed.
|
* external symbols do not need to be upgraded since this is effectively where all the moved
|
||||||
* The triggering of this upgrade relies on the addition of the VariableManager which
|
* external addresses will be placed. The triggering of this upgrade relies on the addition of
|
||||||
* trigger an upgrade.
|
* the VariableManager which trigger an upgrade.
|
||||||
|
*
|
||||||
* @param monitor the task monitor
|
* @param monitor the task monitor
|
||||||
*/
|
*/
|
||||||
private boolean upgradeOldNamespaceAddresses(TaskMonitor monitor)
|
private boolean upgradeOldNamespaceAddresses(TaskMonitor monitor)
|
||||||
throws IOException, CancelledException {
|
throws IOException, CancelledException {
|
||||||
|
|
||||||
ReferenceDBManager refMgr = (ReferenceDBManager) program.getReferenceManager();
|
ReferenceDBManager refMgr = program.getReferenceManager();
|
||||||
|
|
||||||
Address nextExtAddr = getNextExternalSymbolAddress();
|
Address nextExtAddr = getNextExternalSymbolAddress();
|
||||||
|
|
||||||
|
@ -236,7 +239,9 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Upgrade old stack and register variable symbol address to variable addresses.
|
* Upgrade old stack and register variable symbol address to variable addresses.
|
||||||
|
* <p>
|
||||||
* Also force associated references to be updated to new variable addresses.
|
* Also force associated references to be updated to new variable addresses.
|
||||||
|
*
|
||||||
* @param monitor the task monitor
|
* @param monitor the task monitor
|
||||||
* @throws IOException if there is database exception
|
* @throws IOException if there is database exception
|
||||||
* @throws CancelledException if the operation is cancelled
|
* @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.
|
* No more sharing the same variable address for multiple variable symbols.
|
||||||
* Must split these up. Only reference to variable addresses should be the
|
* <p>
|
||||||
* symbol address - reference refer to physical/stack addresses, and symbolIDs.
|
* 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
|
* @param monitor the task monitor
|
||||||
* @throws CancelledException if the operation is cancelled
|
* @throws CancelledException if the operation is cancelled
|
||||||
*/
|
*/
|
||||||
|
@ -394,6 +401,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add old local symbols
|
* Add old local symbols
|
||||||
|
*
|
||||||
* @throws IOException if there is database exception
|
* @throws IOException if there is database exception
|
||||||
* @throws CancelledException if the operation is cancelled
|
* @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
|
* Save off old local symbols whose upgrade needs to be deferred until after function manager
|
||||||
* upgrade has been completed.
|
* upgrade has been completed.
|
||||||
|
*
|
||||||
* @param tmpHandle scratch pad database handle
|
* @param tmpHandle scratch pad database handle
|
||||||
* @param symbolID local symbol ID
|
* @param symbolID local symbol ID
|
||||||
* @param oldAddr old address value from symbol table
|
* @param oldAddr old address value from symbol table
|
||||||
|
@ -628,7 +637,6 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//refManager.symbolRemoved(sym);
|
|
||||||
return sym.delete();
|
return sym.delete();
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
|
@ -661,6 +669,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes the symbol directly
|
* Removes the symbol directly
|
||||||
|
*
|
||||||
* @param sym the symbol to remove.
|
* @param sym the symbol to remove.
|
||||||
* @return true if the symbol was removed, false otherwise.
|
* @return true if the symbol was removed, false otherwise.
|
||||||
*/
|
*/
|
||||||
|
@ -1144,6 +1153,21 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
||||||
return null;
|
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
|
@Override
|
||||||
public Symbol getPrimarySymbol(Address addr) {
|
public Symbol getPrimarySymbol(Address addr) {
|
||||||
if (!addr.isMemoryAddress() && !addr.isExternalAddress()) {
|
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.
|
* Returns the maximum symbol address within the specified address space.
|
||||||
|
*
|
||||||
* @param space address space
|
* @param space address space
|
||||||
* @return maximum symbol address within space or null if none are found.
|
* @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
|
* Returns the next available external symbol address
|
||||||
|
*
|
||||||
* @return the address
|
* @return the address
|
||||||
*/
|
*/
|
||||||
public Address getNextExternalSymbolAddress() {
|
public Address getNextExternalSymbolAddress() {
|
||||||
|
@ -1228,14 +1254,18 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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(
|
return getPrimarySymbolIterator(
|
||||||
program.getAddressFactory().getAddressSet(startAddr, program.getMaxAddress()), forward);
|
program.getAddressFactory().getAddressSet(startAddr, program.getMaxAddress()), forward);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SymbolIterator getPrimarySymbolIterator(AddressSetView set, boolean forward) {
|
public SymbolIterator getPrimarySymbolIterator(AddressSetView set, boolean forward) {
|
||||||
if (set.isEmpty()) {
|
if (set != null && set.isEmpty()) {
|
||||||
return SymbolIterator.EMPTY_ITERATOR;
|
return SymbolIterator.EMPTY_ITERATOR;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
@ -1250,7 +1280,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SymbolIterator getSymbols(AddressSetView set, SymbolType type, boolean forward) {
|
public SymbolIterator getSymbols(AddressSetView set, SymbolType type, boolean forward) {
|
||||||
if (set.isEmpty()) {
|
if (set != null && set.isEmpty()) {
|
||||||
return SymbolIterator.EMPTY_ITERATOR;
|
return SymbolIterator.EMPTY_ITERATOR;
|
||||||
}
|
}
|
||||||
Query query =
|
Query query =
|
||||||
|
@ -1264,7 +1294,11 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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;
|
RecordIterator it;
|
||||||
try {
|
try {
|
||||||
it = adapter.getSymbolsByAddress(startAddr, forward);
|
it = adapter.getSymbolsByAddress(startAddr, forward);
|
||||||
|
@ -1315,7 +1349,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addExternalEntryPoint(Address addr) {
|
public void addExternalEntryPoint(Address addr) throws IllegalArgumentException {
|
||||||
refManager.addExternalEntryPointRef(addr);
|
refManager.addExternalEntryPointRef(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1394,10 +1428,12 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Move symbol. Only symbol address is changed.
|
* Move symbol.
|
||||||
* References must be moved separately.
|
* <p>
|
||||||
* @param oldAddr the old symbol address
|
* Only symbol address is changed. References must be moved separately.
|
||||||
* @param newAddr the new symbol address
|
*
|
||||||
|
* @param oldAddr the old symbol memory address
|
||||||
|
* @param newAddr the new symbol memory address
|
||||||
*/
|
*/
|
||||||
public void moveSymbolsAt(Address oldAddr, Address newAddr) {
|
public void moveSymbolsAt(Address oldAddr, Address newAddr) {
|
||||||
lock.acquire();
|
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
|
// 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
|
// high-order bit set to avoid potential conflict with stored symbol ID's which are
|
||||||
// assigned starting at 0.
|
// assigned starting at 0.
|
||||||
|
if (!addr.isMemoryAddress()) {
|
||||||
|
throw new IllegalArgumentException("Invalid memory address: " + addr);
|
||||||
|
}
|
||||||
return dynamicSymbolAddressMap.getKey(addr);
|
return dynamicSymbolAddressMap.getKey(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1450,16 +1489,17 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
||||||
}
|
}
|
||||||
|
|
||||||
FunctionManagerDB getFunctionManager() {
|
FunctionManagerDB getFunctionManager() {
|
||||||
return (FunctionManagerDB) program.getFunctionManager();
|
return program.getFunctionManager();
|
||||||
}
|
}
|
||||||
|
|
||||||
ExternalManagerDB getExternalManager() {
|
ExternalManagerDB getExternalManager() {
|
||||||
return (ExternalManagerDB) program.getExternalManager();
|
return program.getExternalManager();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by the NamespaceManager when a namespace is removed; remove all symbols that have the
|
* Called by the NamespaceManager when a namespace is removed; remove all symbols that have the
|
||||||
* given namespace ID.
|
* given namespace ID.
|
||||||
|
*
|
||||||
* @param namespaceID ID of namespace being removed
|
* @param namespaceID ID of namespace being removed
|
||||||
*/
|
*/
|
||||||
public void namespaceRemoved(long namespaceID) {
|
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;
|
private RecordIterator it;
|
||||||
|
|
||||||
SymbolNameRecordIterator(String name) throws IOException {
|
AbstractSymbolNameRecordIterator(RecordIterator it) {
|
||||||
this.it = adapter.getSymbolsByName(name);
|
this.it = it;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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 class ExternalSymbolNameRecordIterator implements SymbolIterator {
|
||||||
|
|
||||||
private RecordIterator it;
|
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
|
* 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
|
* @param set the set of addresses that may have to be fixed up
|
||||||
*/
|
*/
|
||||||
private void fixupPrimarySymbols(Set<Address> set) {
|
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
|
* @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) {
|
private boolean hasValidPrimary(Symbol[] symbols) {
|
||||||
if (symbols.length == 0) {
|
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.
|
* Creates variable symbols.
|
||||||
* It is intended to be used by Ghidra program internals.
|
* <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 name the name of the variable
|
||||||
* @param function the function that contains the variable.
|
* @param function the function that contains the variable.
|
||||||
* @param type the type of the variable (can only be PARAMETER or LOCAL_VAR)
|
* @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
|
* Create a Library symbol with the specified name and optional pathname
|
||||||
|
*
|
||||||
* @param name library name
|
* @param name library name
|
||||||
* @param pathname project file path (may be null)
|
* @param pathname project file path (may be null)
|
||||||
* @param source symbol source
|
* @param source symbol source
|
||||||
|
@ -2664,6 +2724,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a Class symbol with the specified name and parent
|
* Create a Class symbol with the specified name and parent
|
||||||
|
*
|
||||||
* @param name class name
|
* @param name class name
|
||||||
* @param parent parent namespace (may be null for global namespace)
|
* @param parent parent namespace (may be null for global namespace)
|
||||||
* @param source symbol source
|
* @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
|
* Create a simple Namespace symbol with the specified name and parent
|
||||||
|
*
|
||||||
* @param name class name
|
* @param name class name
|
||||||
* @param parent parent namespace (may be null for global namespace)
|
* @param parent parent namespace (may be null for global namespace)
|
||||||
* @param source symbol source
|
* @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
|
* Internal method for creating label symbols.
|
||||||
* it will be returned.
|
* <p>
|
||||||
|
* If identical memory symbol already exists it will be returned.
|
||||||
|
*
|
||||||
* @param addr the address for the new symbol (memory or external)
|
* @param addr the address for the new symbol (memory or external)
|
||||||
* @param name the name of 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 source the SourceType of the new symbol
|
||||||
* @param stringData special use depending on the symbol type and whether or not it is external
|
* @param stringData special use depending on the symbol type and whether or not it is external
|
||||||
* @return the new symbol
|
* @return the new symbol
|
||||||
|
@ -2771,14 +2836,14 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
||||||
makePrimary = (primary == null);
|
makePrimary = (primary == null);
|
||||||
}
|
}
|
||||||
else if (addr.isExternalAddress()) {
|
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);
|
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");
|
throw new IllegalArgumentException("external address already used");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
throw new IllegalArgumentException("bad label address");
|
throw new IllegalArgumentException("Invalid memory address: " + addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
return doCreateSymbol(name, addr, namespace, SymbolType.LABEL, stringData, null, null,
|
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 addr the address for the new symbol
|
||||||
* @param name the name of 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 source the SourceType of the new symbol
|
||||||
* @param stringData special use depending on the symbol type and whether or not it is external.
|
* @param stringData special use depending on the symbol type and whether or not it is external.
|
||||||
* @return the new symbol
|
* @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
|
* Finds the appropriate symbol to promote when function is created.
|
||||||
* mean find the symbol that needs to be deleted before creating the function symbol. If the
|
* <p>
|
||||||
* found symbol is not dynamic, the function symbol will assume its name and namespace.
|
* 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) {
|
private Symbol findSymbolToPromote(Symbol matching, Symbol primary, SourceType source) {
|
||||||
// if the function is default, then the primary will be promoted
|
// 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.*;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.*;
|
||||||
|
@ -85,7 +86,7 @@ public class SymbolUtilities {
|
||||||
DEFAULT_DATA_PREFIX, DEFAULT_SYMBOL_PREFIX, DEFAULT_SUBROUTINE_PREFIX,
|
DEFAULT_DATA_PREFIX, DEFAULT_SYMBOL_PREFIX, DEFAULT_SUBROUTINE_PREFIX,
|
||||||
DEFAULT_UNKNOWN_PREFIX, DEFAULT_EXTERNAL_ENTRY_PREFIX, DEFAULT_FUNCTION_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
|
* 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) {
|
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)) {
|
if (name.startsWith(UNDERSCORE)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -591,7 +592,7 @@ public class SymbolUtilities {
|
||||||
space = factory.getDefaultAddressSpace();
|
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) {
|
if (addressOffsetString.length() < MIN_LABEL_ADDRESS_DIGITS) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -172,6 +172,11 @@ public class StubSymbolTable implements SymbolTable {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SymbolIterator scanSymbolsByName(String startName) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getNumSymbols() {
|
public int getNumSymbols() {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue