mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 02:39:44 +02:00
GT-3348 fixing stale dynamic symbol names
This commit is contained in:
parent
c15b263b90
commit
cec9d954ed
3 changed files with 149 additions and 21 deletions
|
@ -22,11 +22,13 @@ import java.util.*;
|
||||||
import org.junit.*;
|
import org.junit.*;
|
||||||
|
|
||||||
import generic.test.TestUtils;
|
import generic.test.TestUtils;
|
||||||
|
import ghidra.app.cmd.disassemble.DisassembleCommand;
|
||||||
import ghidra.app.cmd.function.CreateFunctionCmd;
|
import ghidra.app.cmd.function.CreateFunctionCmd;
|
||||||
import ghidra.program.database.ProgramBuilder;
|
import ghidra.program.database.ProgramBuilder;
|
||||||
import ghidra.program.database.ProgramDB;
|
import ghidra.program.database.ProgramDB;
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.data.ByteDataType;
|
import ghidra.program.model.data.ByteDataType;
|
||||||
|
import ghidra.program.model.data.WordDataType;
|
||||||
import ghidra.program.model.listing.*;
|
import ghidra.program.model.listing.*;
|
||||||
import ghidra.program.model.mem.Memory;
|
import ghidra.program.model.mem.Memory;
|
||||||
import ghidra.program.model.mem.MemoryBlock;
|
import ghidra.program.model.mem.MemoryBlock;
|
||||||
|
@ -216,6 +218,124 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
assertTrue(s[0].getSource() == SourceType.DEFAULT);
|
assertTrue(s[0].getSource() == SourceType.DEFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDynamicNameChangesWhenDataApplied() throws Exception {
|
||||||
|
refMgr.addMemoryReference(addr(512), addr(256), RefType.FLOW, SourceType.USER_DEFINED, -1);
|
||||||
|
Symbol[] s = st.getSymbols(addr(256));
|
||||||
|
assertEquals(1, s.length);
|
||||||
|
assertEquals("LAB_00000100", s[0].getName());
|
||||||
|
program.getListing().createData(addr(256), new ByteDataType());
|
||||||
|
assertEquals("BYTE_00000100", s[0].getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDynamicNameChangesWhenDataCleared() throws Exception {
|
||||||
|
refMgr.addMemoryReference(addr(512), addr(256), RefType.FLOW, SourceType.USER_DEFINED, -1);
|
||||||
|
program.getListing().createData(addr(256), new ByteDataType());
|
||||||
|
Symbol[] s = st.getSymbols(addr(256));
|
||||||
|
assertEquals(1, s.length);
|
||||||
|
assertEquals("BYTE_00000100", s[0].getName());
|
||||||
|
|
||||||
|
program.getListing().clearCodeUnits(addr(256), addr(256), false);
|
||||||
|
assertEquals("LAB_00000100", s[0].getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDynamicOffcutNameChangesWhenSymbolCreated() throws Exception {
|
||||||
|
refMgr.addMemoryReference(addr(512), addr(257), RefType.FLOW, SourceType.USER_DEFINED, -1);
|
||||||
|
program.getListing().createData(addr(256), new WordDataType());
|
||||||
|
|
||||||
|
Symbol[] s = st.getSymbols(addr(257));
|
||||||
|
assertEquals(1, s.length);
|
||||||
|
assertEquals("WORD_00000100+1", s[0].getName());
|
||||||
|
st.createLabel(addr(256), "bob", SourceType.USER_DEFINED);
|
||||||
|
assertEquals("bob+1", s[0].getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDynamicOffcutNameChangesWhenSymbolRenamed() throws Exception {
|
||||||
|
refMgr.addMemoryReference(addr(512), addr(257), RefType.FLOW, SourceType.USER_DEFINED, -1);
|
||||||
|
program.getListing().createData(addr(256), new WordDataType());
|
||||||
|
Symbol label = st.createLabel(addr(256), "bob", SourceType.USER_DEFINED);
|
||||||
|
|
||||||
|
Symbol[] s = st.getSymbols(addr(257));
|
||||||
|
assertEquals(1, s.length);
|
||||||
|
assertEquals("bob+1", s[0].getName());
|
||||||
|
label.setName("fred", SourceType.USER_DEFINED);
|
||||||
|
assertEquals("fred+1", s[0].getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDynamicOffcutNameChangesWhenSymbolRemoved() throws Exception {
|
||||||
|
refMgr.addMemoryReference(addr(512), addr(257), RefType.FLOW, SourceType.USER_DEFINED, -1);
|
||||||
|
program.getListing().createData(addr(256), new WordDataType());
|
||||||
|
Symbol label = st.createLabel(addr(256), "bob", SourceType.USER_DEFINED);
|
||||||
|
|
||||||
|
Symbol[] s = st.getSymbols(addr(257));
|
||||||
|
assertEquals(1, s.length);
|
||||||
|
assertEquals("bob+1", s[0].getName());
|
||||||
|
label.delete();
|
||||||
|
assertEquals("WORD_00000100+1", s[0].getName());
|
||||||
|
}
|
||||||
|
@Test
|
||||||
|
public void testDynamicNameChangesWhenOffcutByInstruction() throws Exception {
|
||||||
|
refMgr.addMemoryReference(addr(512), addr(257), RefType.FLOW, SourceType.USER_DEFINED, -1);
|
||||||
|
|
||||||
|
Symbol[] s = st.getSymbols(addr(257));
|
||||||
|
assertEquals(1, s.length);
|
||||||
|
assertEquals("LAB_00000101", s[0].getName());
|
||||||
|
createInstruction(addr(256));
|
||||||
|
CodeUnit codeUnitAt = program.getListing().getCodeUnitAt(addr(256));
|
||||||
|
assertTrue(codeUnitAt instanceof Instruction);
|
||||||
|
assertEquals(2, codeUnitAt.getLength());
|
||||||
|
|
||||||
|
assertEquals("LAB_00000100+1", s[0].getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDynamicNameChangesWhenCallRefAdded() throws Exception {
|
||||||
|
refMgr.addMemoryReference(addr(512), addr(256), RefType.FLOW, SourceType.USER_DEFINED, -1);
|
||||||
|
|
||||||
|
Symbol[] s = st.getSymbols(addr(256));
|
||||||
|
assertEquals(1, s.length);
|
||||||
|
assertEquals("LAB_00000100", s[0].getName());
|
||||||
|
|
||||||
|
refMgr.addMemoryReference(addr(512), addr(256), RefType.UNCONDITIONAL_CALL,
|
||||||
|
SourceType.USER_DEFINED, -1);
|
||||||
|
|
||||||
|
assertEquals("SUB_00000100", s[0].getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDynamicNameChangesWhenCallRefRemoved() throws Exception {
|
||||||
|
refMgr.addMemoryReference(addr(512), addr(256), RefType.FLOW, SourceType.USER_DEFINED, -1);
|
||||||
|
Reference ref = refMgr.addMemoryReference(addr(516), addr(256), RefType.UNCONDITIONAL_CALL,
|
||||||
|
SourceType.USER_DEFINED, -1);
|
||||||
|
|
||||||
|
Symbol[] s = st.getSymbols(addr(256));
|
||||||
|
assertEquals(1, s.length);
|
||||||
|
assertEquals("SUB_00000100", s[0].getName());
|
||||||
|
|
||||||
|
refMgr.delete(ref);
|
||||||
|
assertEquals("LAB_00000100", s[0].getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void createInstruction(Address addr) throws Exception {
|
||||||
|
int tx = program.startTransaction("test");
|
||||||
|
try {
|
||||||
|
Memory memory = program.getMemory();
|
||||||
|
memory.setByte(addr, (byte) 0xd9);
|
||||||
|
memory.setByte(addr, (byte) 0x32);
|
||||||
|
AddressSet set = new AddressSet(addr, addr.add(1));
|
||||||
|
DisassembleCommand cmd = new DisassembleCommand(set, set);
|
||||||
|
cmd.applyTo(program);
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
program.endTransaction(tx, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetDefaultFunctionSymbolByName() throws Exception {
|
public void testGetDefaultFunctionSymbolByName() throws Exception {
|
||||||
Listing listing = program.getListing();
|
Listing listing = program.getListing();
|
||||||
|
|
|
@ -45,11 +45,13 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
|
||||||
|
|
||||||
private Record record;
|
private Record record;
|
||||||
private boolean isDeleting = false;
|
private boolean isDeleting = false;
|
||||||
protected String name;
|
|
||||||
protected Address address;
|
protected Address address;
|
||||||
protected SymbolManager symbolMgr;
|
protected SymbolManager symbolMgr;
|
||||||
protected Lock lock;
|
protected Lock lock;
|
||||||
|
|
||||||
|
private String cachedName;
|
||||||
|
private long cachedNameModCount;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a Symbol that is just a placeholder for use when trying to find symbols by using
|
* Creates a Symbol that is just a placeholder for use when trying to find symbols by using
|
||||||
* {@link Symbol#getID()}. This is useful for locating symbols in Java collections when
|
* {@link Symbol#getID()}. This is useful for locating symbols in Java collections when
|
||||||
|
@ -83,7 +85,7 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
// prefer cached name for speed; it may be stale; call getName() for current value
|
// prefer cached name for speed; it may be stale; call getName() for current value
|
||||||
String temp = name;
|
String temp = cachedName;
|
||||||
if (temp != null) {
|
if (temp != null) {
|
||||||
return temp;
|
return temp;
|
||||||
}
|
}
|
||||||
|
@ -97,7 +99,6 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean refresh(Record rec) {
|
protected boolean refresh(Record rec) {
|
||||||
name = null;
|
|
||||||
if (record != null) {
|
if (record != null) {
|
||||||
if (rec == null) {
|
if (rec == null) {
|
||||||
rec = symbolMgr.getSymbolRecord(key);
|
rec = symbolMgr.getSymbolRecord(key);
|
||||||
|
@ -164,20 +165,31 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public final String getName() {
|
||||||
|
String name = cachedName;
|
||||||
|
if (hasValidCachedName(name)) {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
lock.acquire();
|
lock.acquire();
|
||||||
try {
|
try {
|
||||||
checkIsValid();
|
checkIsValid();
|
||||||
if (name == null) {
|
cachedName = doGetName();
|
||||||
name = doGetName();
|
cachedNameModCount = symbolMgr.getProgram().getModificationNumber();
|
||||||
}
|
return cachedName;
|
||||||
return name;
|
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
lock.release();
|
lock.release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean hasValidCachedName(String name) {
|
||||||
|
if (name == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return symbolMgr.getProgram().getModificationNumber() == cachedNameModCount;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The code for creating the name content for this symbol. This code will be called
|
* The code for creating the name content for this symbol. This code will be called
|
||||||
* with the symbol's lock.
|
* with the symbol's lock.
|
||||||
|
@ -521,7 +533,6 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
|
||||||
|
|
||||||
lock.acquire();
|
lock.acquire();
|
||||||
try {
|
try {
|
||||||
name = null;
|
|
||||||
checkDeleted();
|
checkDeleted();
|
||||||
checkEditOK();
|
checkEditOK();
|
||||||
|
|
||||||
|
@ -575,10 +586,10 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
|
||||||
|
|
||||||
record.setLongValue(SymbolDatabaseAdapter.SYMBOL_PARENT_COL, newNamespace.getID());
|
record.setLongValue(SymbolDatabaseAdapter.SYMBOL_PARENT_COL, newNamespace.getID());
|
||||||
record.setString(SymbolDatabaseAdapter.SYMBOL_NAME_COL, newName);
|
record.setString(SymbolDatabaseAdapter.SYMBOL_NAME_COL, newName);
|
||||||
name = newName;
|
|
||||||
updateSymbolSource(record, source);
|
updateSymbolSource(record, source);
|
||||||
updateRecord();
|
updateRecord();
|
||||||
|
cachedName = null; // we can't clear it until now, since any call to getName()
|
||||||
|
// will cause the cached name to reset to the old name
|
||||||
if (namespaceChange) {
|
if (namespaceChange) {
|
||||||
symbolMgr.symbolNamespaceChanged(this, oldNamespace);
|
symbolMgr.symbolNamespaceChanged(this, oldNamespace);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/* ###
|
/* ###
|
||||||
* IP: GHIDRA
|
* IP: GHIDRA
|
||||||
* REVIEWED: YES
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -16,6 +15,11 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.program.database.symbol;
|
package ghidra.program.database.symbol;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import db.*;
|
||||||
import ghidra.program.database.map.*;
|
import ghidra.program.database.map.*;
|
||||||
import ghidra.program.database.util.DatabaseTableUtils;
|
import ghidra.program.database.util.DatabaseTableUtils;
|
||||||
import ghidra.program.database.util.RecordFilter;
|
import ghidra.program.database.util.RecordFilter;
|
||||||
|
@ -25,12 +29,6 @@ import ghidra.program.model.symbol.*;
|
||||||
import ghidra.util.exception.*;
|
import ghidra.util.exception.*;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import db.*;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SymbolDatabaseAdapter for version 2
|
* SymbolDatabaseAdapter for version 2
|
||||||
*/
|
*/
|
||||||
|
@ -183,13 +181,12 @@ class SymbolDatabaseAdapterV2 extends SymbolDatabaseAdapter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
|
||||||
* @see ghidra.program.database.symbol.SymbolDatabaseAdapter#createSymbol(java.lang.String, ghidra.program.model.address.Address, long, ghidra.program.model.symbol.SymbolType, long, int, int)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
Record createSymbol(String name, Address address, long namespaceID, SymbolType symbolType,
|
Record createSymbol(String name, Address address, long namespaceID, SymbolType symbolType,
|
||||||
long data1, int data2, String data3, SourceType source) throws IOException {
|
long data1, int data2, String data3, SourceType source) throws IOException {
|
||||||
long nextID = symbolTable.getKey();
|
long nextID = symbolTable.getKey();
|
||||||
|
|
||||||
|
// avoiding key 0, because we use the negative of the address offset as keys for dynamic symbols
|
||||||
if (nextID == 0) {
|
if (nextID == 0) {
|
||||||
nextID++;
|
nextID++;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue