Merge remote-tracking branch

'origin/GP-5453-dragonmacher-decompiler-locations--SQUASHED'
(Closes #7518)
This commit is contained in:
Ryan Kurtz 2025-04-23 10:41:42 -04:00
commit 4aa78ae6d0
25 changed files with 880 additions and 322 deletions

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -19,12 +19,10 @@ import db.DBRecord;
import ghidra.program.database.DBObjectCache;
import ghidra.program.model.address.Address;
import ghidra.program.model.symbol.*;
import ghidra.program.util.ProgramLocation;
/**
* Symbols that represent "classes"
* Symbols that represent classes
*/
public class ClassSymbol extends SymbolDB {
private GhidraClassDB ghidraClass;
@ -42,17 +40,11 @@ public class ClassSymbol extends SymbolDB {
}
/**
* @see ghidra.program.model.symbol.Symbol#getSymbolType()
*/
@Override
public SymbolType getSymbolType() {
return SymbolType.CLASS;
}
/**
* @see ghidra.program.model.symbol.Symbol#getObject()
*/
@Override
public Object getObject() {
lock.acquire();
@ -68,9 +60,6 @@ public class ClassSymbol extends SymbolDB {
}
}
/**
* @see ghidra.program.model.symbol.Symbol#isPrimary()
*/
@Override
public boolean isPrimary() {
return true;
@ -82,17 +71,6 @@ public class ClassSymbol extends SymbolDB {
return parentSymbol != null ? parentSymbol.isExternal() : false;
}
/**
* @see ghidra.program.model.symbol.Symbol#getProgramLocation()
*/
@Override
public ProgramLocation getProgramLocation() {
return null;
}
/**
* @see ghidra.program.model.symbol.Symbol#isValidParent(ghidra.program.model.symbol.Namespace)
*/
@Override
public boolean isValidParent(Namespace parent) {
return super.isValidParent(parent) &&

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -32,7 +32,6 @@ import ghidra.program.util.ProgramLocation;
* EXTERNAL:
* String stringData - external memory address/label
*/
public class CodeSymbol extends SymbolDB {
/**
@ -58,9 +57,6 @@ public class CodeSymbol extends SymbolDB {
super(mgr, cache, addr, key);
}
/**
* @see ghidra.program.model.symbol.Symbol#getSymbolType()
*/
@Override
public SymbolType getSymbolType() {
return SymbolType.LABEL;
@ -124,9 +120,6 @@ public class CodeSymbol extends SymbolDB {
}
}
/**
* @see ghidra.program.model.symbol.Symbol#getObject()
*/
@Override
public Object getObject() {
lock.acquire();
@ -155,9 +148,6 @@ public class CodeSymbol extends SymbolDB {
return null;
}
/**
* @see ghidra.program.model.symbol.Symbol#isPrimary()
*/
@Override
public boolean isPrimary() {
if (getSource() == SourceType.DEFAULT || isExternal()) {
@ -166,9 +156,6 @@ public class CodeSymbol extends SymbolDB {
return doCheckIsPrimary();
}
/**
* @see ghidra.program.model.symbol.Symbol#setPrimary()
*/
@Override
public boolean setPrimary() {
lock.acquire();
@ -205,17 +192,11 @@ public class CodeSymbol extends SymbolDB {
doSetPrimary(primary);
}
/**
* @see ghidra.program.model.symbol.Symbol#getProgramLocation()
*/
@Override
public ProgramLocation getProgramLocation() {
return new LabelFieldLocation(this);
}
/**
* @see ghidra.program.model.symbol.Symbol#isValidParent(ghidra.program.model.symbol.Namespace)
*/
@Override
public boolean isValidParent(Namespace parent) {
return super.isValidParent(parent) &&

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -57,9 +57,6 @@ public class FunctionSymbol extends SymbolDB {
this.functionMgr = symbolMgr.getFunctionManager();
}
/**
* @see ghidra.program.model.symbol.Symbol#getSymbolType()
*/
@Override
public SymbolType getSymbolType() {
return SymbolType.FUNCTION;

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -22,7 +22,6 @@ import ghidra.program.model.listing.CircularDependencyException;
import ghidra.program.model.listing.Library;
import ghidra.program.model.symbol.*;
import ghidra.program.util.ProgramEvent;
import ghidra.program.util.ProgramLocation;
import ghidra.util.Msg;
import ghidra.util.exception.DuplicateNameException;
import ghidra.util.exception.InvalidInputException;
@ -33,7 +32,6 @@ import ghidra.util.exception.InvalidInputException;
* Symbol data usage:
* String stringData - associated program project file path
*/
public class LibrarySymbol extends SymbolDB {
private LibraryDB library;
@ -93,6 +91,7 @@ public class LibrarySymbol extends SymbolDB {
.setObjChanged(ProgramEvent.EXTERNAL_PATH_CHANGED, getName(), oldPath, newPath);
}
@Override
public SymbolType getSymbolType() {
return SymbolType.LIBRARY;
}
@ -115,14 +114,6 @@ public class LibrarySymbol extends SymbolDB {
return true;
}
/**
* @see ghidra.program.model.symbol.Symbol#getProgramLocation()
*/
public ProgramLocation getProgramLocation() {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean isValidParent(Namespace parent) {
return super.isValidParent(parent) &&

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -19,15 +19,13 @@ import db.DBRecord;
import ghidra.program.database.DBObjectCache;
import ghidra.program.model.address.Address;
import ghidra.program.model.symbol.*;
import ghidra.program.util.ProgramLocation;
/**
* Symbol class for namespaces.
*/
public class NamespaceSymbol extends SymbolDB {
NamespaceDB namespace;
private NamespaceDB namespace;
/**
* Construct a new namespace symbol
@ -36,13 +34,11 @@ public class NamespaceSymbol extends SymbolDB {
* @param addr the address for this symbol.
* @param record the record for this symbol.
*/
NamespaceSymbol(SymbolManager mgr, DBObjectCache<SymbolDB> cache, Address addr, DBRecord record) {
NamespaceSymbol(SymbolManager mgr, DBObjectCache<SymbolDB> cache, Address addr,
DBRecord record) {
super(mgr, cache, addr, record);
}
/**
* @see ghidra.program.database.symbol.SymbolDB#isPrimary()
*/
@Override
public boolean isPrimary() {
return true;
@ -54,25 +50,11 @@ public class NamespaceSymbol extends SymbolDB {
return parentSymbol != null ? parentSymbol.isExternal() : false;
}
/**
* @see ghidra.program.model.symbol.Symbol#getSymbolType()
*/
@Override
public SymbolType getSymbolType() {
return SymbolType.NAMESPACE;
}
/**
* @see ghidra.program.model.symbol.Symbol#getProgramLocation()
*/
@Override
public ProgramLocation getProgramLocation() {
return null;
}
/**
* @see ghidra.program.model.symbol.Symbol#getObject()
*/
@Override
public Object getObject() {
return getNamespace();
@ -85,9 +67,6 @@ public class NamespaceSymbol extends SymbolDB {
return namespace;
}
/**
* @see ghidra.program.model.symbol.Symbol#isValidParent(ghidra.program.model.symbol.Namespace)
*/
@Override
public boolean isValidParent(Namespace parent) {
// TODO: Not sure what other constraints should be placed on namespace movement

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -100,9 +100,6 @@ public class VariableSymbolDB extends SymbolDB {
return variableStorage;
}
/**
* @see ghidra.program.model.symbol.Symbol#getSymbolType()
*/
@Override
public SymbolType getSymbolType() {
return type;
@ -115,18 +112,12 @@ public class VariableSymbolDB extends SymbolDB {
return isValid;
}
/**
* @see ghidra.program.database.symbol.SymbolDB#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
// TODO: not sure what constitutes equality since address will differ
return obj == this;
}
/**
* @see ghidra.program.model.symbol.Symbol#delete()
*/
@Override
public boolean delete() {
lock.acquire();
@ -146,9 +137,6 @@ public class VariableSymbolDB extends SymbolDB {
}
}
/**
* @see ghidra.program.model.symbol.Symbol#getObject()
*/
@Override
public Object getObject() {
FunctionDB func = getFunction();
@ -158,9 +146,6 @@ public class VariableSymbolDB extends SymbolDB {
return null;
}
/**
* @see ghidra.program.model.symbol.Symbol#isPrimary()
*/
@Override
public boolean isPrimary() {
return false;
@ -178,9 +163,6 @@ public class VariableSymbolDB extends SymbolDB {
getParentNamespace().getID());
}
/**
* @see ghidra.program.model.symbol.Symbol#getProgramLocation()
*/
@Override
public ProgramLocation getProgramLocation() {
Variable var = (Variable) getObject();
@ -190,9 +172,6 @@ public class VariableSymbolDB extends SymbolDB {
return null;
}
/**
* @see ghidra.program.model.symbol.Symbol#isValidParent(ghidra.program.model.symbol.Namespace)
*/
@Override
public boolean isValidParent(Namespace parent) {
// symbol is locked to single function and can't be moved
@ -270,9 +249,8 @@ public class VariableSymbolDB extends SymbolDB {
}
/**
* Change the storage address and data-type associated with this
* variable symbol.
* @param newStorage
* Change the storage address and data-type associated with this variable symbol.
* @param newStorage the new storage
* @param dt data-type
*/
public void setStorageAndDataType(VariableStorage newStorage, DataType dt) {

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -18,7 +18,6 @@ package ghidra.program.model.address;
import ghidra.program.model.listing.CircularDependencyException;
import ghidra.program.model.listing.Program;
import ghidra.program.model.symbol.*;
import ghidra.program.util.ProgramLocation;
import ghidra.util.exception.DuplicateNameException;
import ghidra.util.exception.InvalidInputException;
import ghidra.util.task.TaskMonitor;
@ -140,11 +139,6 @@ public class GlobalSymbol implements Symbol {
return new Reference[0];
}
@Override
public ProgramLocation getProgramLocation() {
return null;
}
@Override
public void setName(String newName, SourceType source)
throws DuplicateNameException, InvalidInputException {

View file

@ -385,6 +385,44 @@ public class HighFunctionDBUtil {
return res;
}
private static Variable getLocalVariable(Function function, VariableStorage storage,
Address pcAddr) {
if (storage.isHashStorage()) {
long hashVal = storage.getFirstVarnode().getOffset();
for (Variable ul : function.getLocalVariables(VariableFilter.UNIQUE_VARIABLE_FILTER)) {
// Note: assumes there is only one hash method used for unique locals
if (ul.getFirstStorageVarnode().getOffset() == hashVal) {
return ul;
}
}
return null;
}
int firstUseOffset = 0;
if (pcAddr != null) {
firstUseOffset = (int) pcAddr.subtract(function.getEntryPoint());
}
for (Variable otherVar : function.getLocalVariables()) {
if (otherVar.getFirstUseOffset() != firstUseOffset) {
// other than parameters we will have a hard time identifying
// local variable conflicts due to differences in scope (i.e., first-use)
continue;
}
VariableStorage otherStorage = otherVar.getVariableStorage();
if (otherStorage.intersects(storage)) {
if (otherStorage.equals(storage)) {
return otherVar;
}
}
}
return null;
}
/**
* Low-level routine for clearing any variables in the
* database which conflict with this variable and return
@ -477,6 +515,38 @@ public class HighFunctionDBUtil {
return parameters[slot];
}
public static Variable getFunctionVariable(HighSymbol highSymbol) {
HighFunction highFunction = highSymbol.getHighFunction();
Function function = highFunction.getFunction();
HighVariable highVar = highSymbol.getHighVariable();
if (highSymbol.isParameter()) {
int slot = ((HighParam) highVar).getSlot();
Parameter parameter = function.getParameter(slot);
return parameter;
}
if (highSymbol.isGlobal()) {
return null;
}
VariableStorage storage = highSymbol.getStorage();
Address pcAddr = highSymbol.getPCAddress();
Variable localVariable = getLocalVariable(function, storage, pcAddr);
if (!storage.isHashStorage() && highVar != null && highVar.requiresDynamicStorage()) {
DynamicEntry entry = DynamicEntry.build(highVar.getRepresentative());
storage = entry.getStorage();
pcAddr = entry.getPCAdress(); // The address may change from original Varnode
}
if (localVariable != null) {
return localVariable;
}
return null;
}
/**
* Rename and/or retype the specified variable in the database. All parameters may be flushed
* to the database if typed parameter inconsistency detected.

View file

@ -128,9 +128,14 @@ public interface Symbol {
public Reference[] getReferences();
/**
* @return a program location corresponding to this symbol
* Returns a program location for this symbol; may be null. This allows implementations to
* return a more specific program location than what is typically used by the system.
*
* @return the location
*/
public ProgramLocation getProgramLocation();
public default ProgramLocation getProgramLocation() {
return null;
}
/**
* Sets the name this symbol.

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -38,7 +38,7 @@ public class FunctionLocation extends ProgramLocation {
* @param functionAddr the function address
* @param row the row in the field
* @param col the display piece on the row
* @param charOffset the character position within the display piece specifed by row,col
* @param charOffset the character position within the display piece specified by row,col
*/
protected FunctionLocation(Program program, Address locationAddr, Address functionAddr, int row,
int col, int charOffset) {
@ -53,9 +53,6 @@ public class FunctionLocation extends ProgramLocation {
protected FunctionLocation() {
}
/**
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (super.equals(obj)) {

View file

@ -25,18 +25,16 @@ import ghidra.program.model.listing.Program;
import ghidra.program.model.symbol.*;
/**
* The <CODE>LableFieldLocation</CODE> class contains specific location information
* within the LABEL field of a CodeUnitLocation object.
* This class contains specific location information within the label field of a
* {@link CodeUnitLocation}
*/
public class LabelFieldLocation extends CodeUnitLocation {
private SymbolPath symbolPath;
/**
* Default constructor needed for restoring
* a label field location from XML
* Default constructor needed for restoring a label field location from XML
*/
public LabelFieldLocation() {
}
/**
@ -45,8 +43,9 @@ public class LabelFieldLocation extends CodeUnitLocation {
* @param program the program of the location
* @param addr address of the location; should not be null
* @param componentPath array of indexes for each nested data component; the
* index is the data component's index within its parent; may be null
* index is the data component's index within its parent; may be null.
* @param label the label String at this location.
* @param namespace the namespace; may be null.
* @param row the row in list of labels as displayed by the label field. Only used for
* program location comparison purposes.
* @param charOffset the column position within the label string for this location.
@ -113,9 +112,6 @@ public class LabelFieldLocation extends CodeUnitLocation {
}
}
/**
* Return the label string at this location.
*/
public String getName() {
return symbolPath.getName();
}
@ -143,9 +139,6 @@ public class LabelFieldLocation extends CodeUnitLocation {
return symbolPath;
}
/**
* Returns a String representation of this location.
*/
@Override
public String toString() {
return super.toString() + ", Label = " + symbolPath.getPath();

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -48,6 +48,7 @@ public class ProgramLocation implements Cloneable, Comparable<ProgramLocation> {
private int row;
private int col;
private int charOffset;
private boolean hasBeenRestored;
/**
* Construct a new ProgramLocation.
@ -237,24 +238,31 @@ public class ProgramLocation implements Cloneable, Comparable<ProgramLocation> {
/**
* Restore this program location using the given program and save state object.
*
* @param program1 program to restore from
* @param newProgram program to restore from
* @param obj the save state to restore from
*/
public void restoreState(Program program1, SaveState obj) {
this.program = program1;
public void restoreState(Program newProgram, SaveState obj) {
if (hasBeenRestored) {
// ProgramLoations are intended to be immutable. Calling this repeatedly breaks that.
Msg.debug(this, "restoreState() has been called multiple times");
return;
}
hasBeenRestored = true;
program = newProgram;
String addrStr = obj.getString("_ADDRESS", "0");
String byteAddrStr = obj.getString("_BYTE_ADDR", addrStr);
String refAddrStr = obj.getString("_REF_ADDRESS", null);
componentPath = obj.getInts("_COMP_PATH", null);
addr = ProgramUtilities.parseAddress(program1, addrStr);
byteAddr = ProgramUtilities.parseAddress(program1, byteAddrStr);
addr = ProgramUtilities.parseAddress(program, addrStr);
byteAddr = ProgramUtilities.parseAddress(program, byteAddrStr);
if (refAddrStr != null) {
refAddr = ProgramUtilities.parseAddress(program1, refAddrStr);
refAddr = ProgramUtilities.parseAddress(program, refAddrStr);
}
col = obj.getInt("_COLUMN", 0);
row = obj.getInt("_ROW", 0);
charOffset = obj.getInt("_CHAR_OFFSET", 0);
}
/**
@ -271,18 +279,24 @@ public class ProgramLocation implements Cloneable, Comparable<ProgramLocation> {
}
try {
Class<?> locClass = Class.forName(className);
ProgramLocation loc = (ProgramLocation) locClass.getConstructor().newInstance();
Class<?> locationClass = Class.forName(className);
if (locationClass.isInterface()) {
// This check is needed due to a refactoring that has changed a class into an
// interface. The class name may have been saved into the tool. Upon restoring we
// may try to restore that class. If that class is now an interface, the restore
// will not work.
return null;
}
ProgramLocation loc = (ProgramLocation) locationClass.getConstructor().newInstance();
loc.restoreState(program, saveState);
if (loc.getAddress() != null) {
return loc;
}
// no address, it must be in a removed block; we can't use it
}
catch (RuntimeException e) { // state may not parse the address if it is no longer valid
}
catch (ClassNotFoundException e) {
// not sure why we are ignoring this--if you know, then please let everyone else know
// this can happen for locations created by plugins that are no longer installed
}
catch (InstantiationException | IllegalAccessException | NoSuchMethodException e) {
Msg.showError(ProgramLocation.class, null, "Programming Error",

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -68,6 +68,7 @@ public class VariableLocFieldLocation extends VariableLocation {
/**
* Gets the location string. (For stack variables this is the offset as a string.)
* @return the location string
*/
public String getLoc() {
return loc;
@ -83,19 +84,24 @@ public class VariableLocFieldLocation extends VariableLocation {
@Override
public boolean equals(Object obj) {
if (this == obj)
if (this == obj) {
return true;
if (!super.equals(obj))
}
if (!super.equals(obj)) {
return false;
if (getClass() != obj.getClass())
}
if (getClass() != obj.getClass()) {
return false;
}
VariableLocFieldLocation other = (VariableLocFieldLocation) obj;
if (loc == null) {
if (other.loc != null)
if (other.loc != null) {
return false;
}
}
else if (!loc.equals(other.loc))
else if (!loc.equals(other.loc)) {
return false;
}
return true;
}

View file

@ -21,7 +21,6 @@ import java.util.List;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.CircularDependencyException;
import ghidra.program.model.listing.Program;
import ghidra.program.util.ProgramLocation;
import ghidra.util.exception.DuplicateNameException;
import ghidra.util.exception.InvalidInputException;
import ghidra.util.task.TaskMonitor;
@ -98,7 +97,7 @@ public class StubSymbol implements Symbol {
}
@Override
public boolean isValidParent(Namespace parent) {
public boolean isValidParent(Namespace nsParent) {
return false;
}
@ -132,11 +131,6 @@ public class StubSymbol implements Symbol {
return null;
}
@Override
public ProgramLocation getProgramLocation() {
return null;
}
@Override
public void setName(String newName, SourceType source)
throws DuplicateNameException, InvalidInputException {