mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 17:59:46 +02:00
Merge remote-tracking branch
'origin/GP-5453-dragonmacher-decompiler-locations--SQUASHED' (Closes #7518)
This commit is contained in:
commit
4aa78ae6d0
25 changed files with 880 additions and 322 deletions
|
@ -36,6 +36,7 @@ import docking.widgets.fieldpanel.support.FieldLocation;
|
||||||
import generic.Unique;
|
import generic.Unique;
|
||||||
import ghidra.app.decompiler.*;
|
import ghidra.app.decompiler.*;
|
||||||
import ghidra.app.decompiler.component.*;
|
import ghidra.app.decompiler.component.*;
|
||||||
|
import ghidra.app.decompiler.location.DefaultDecompilerLocation;
|
||||||
import ghidra.app.plugin.assembler.*;
|
import ghidra.app.plugin.assembler.*;
|
||||||
import ghidra.app.plugin.assembler.sleigh.sem.*;
|
import ghidra.app.plugin.assembler.sleigh.sem.*;
|
||||||
import ghidra.app.plugin.core.analysis.*;
|
import ghidra.app.plugin.core.analysis.*;
|
||||||
|
@ -1610,10 +1611,14 @@ public class StackUnwinderTest extends AbstractGhidraHeadedDebuggerTest {
|
||||||
FieldLocation fLoc = new FieldLocation(i, j, r, c);
|
FieldLocation fLoc = new FieldLocation(i, j, r, c);
|
||||||
ClangToken token = clangField.getToken(fLoc);
|
ClangToken token = clangField.getToken(fLoc);
|
||||||
if (token != null && tokText.equals(token.getText())) {
|
if (token != null && tokText.equals(token.getText())) {
|
||||||
DecompilerLocation loc = token.getMinAddress() == null ? null
|
|
||||||
: new DecompilerLocation(program, token.getMinAddress(),
|
Address entryPoint = function.getEntryPoint();
|
||||||
function.getEntryPoint(), results, token, i.intValue(),
|
DecompilerLocationInfo info =
|
||||||
0);
|
new DecompilerLocationInfo(entryPoint, results, token,
|
||||||
|
i.intValue(), 0);
|
||||||
|
DefaultDecompilerLocation loc = token.getMinAddress() == null ? null
|
||||||
|
: new DefaultDecompilerLocation(program,
|
||||||
|
token.getMinAddress(), info);
|
||||||
return new HoverLocation(loc, fLoc, field, token);
|
return new HoverLocation(loc, fLoc, field, token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,7 +110,7 @@ public class VariableLocFieldFactory extends AbstractVariableFieldFactory {
|
||||||
VariableProxy variableProxy = (VariableProxy) proxy;
|
VariableProxy variableProxy = (VariableProxy) proxy;
|
||||||
Variable sv = variableProxy.getObject();
|
Variable sv = variableProxy.getObject();
|
||||||
return new VariableLocFieldLocation(sv.getProgram(), variableProxy.getLocationAddress(),
|
return new VariableLocFieldLocation(sv.getProgram(), variableProxy.getLocationAddress(),
|
||||||
variableProxy.getObject(), col);
|
sv, col);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -20,6 +20,7 @@ import java.awt.event.*;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import javax.swing.event.ChangeListener;
|
import javax.swing.event.ChangeListener;
|
||||||
|
@ -873,6 +874,13 @@ public class ListingPanel extends JPanel implements FieldMouseListener, FieldLoc
|
||||||
* @param view the set of address to include in the view.
|
* @param view the set of address to include in the view.
|
||||||
*/
|
*/
|
||||||
public void setView(AddressSetView view) {
|
public void setView(AddressSetView view) {
|
||||||
|
|
||||||
|
AddressIndexMap currentMap = layoutModel.getAddressIndexMap();
|
||||||
|
AddressSetView originalView = currentMap.getOriginalAddressSet();
|
||||||
|
if (Objects.equals(originalView, view)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
layoutModel.setAddressSet(view);
|
layoutModel.setAddressSet(view);
|
||||||
updateProviders();
|
updateProviders();
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@ import ghidra.program.model.listing.Program;
|
||||||
import ghidra.util.datastruct.Duo.Side;
|
import ghidra.util.datastruct.Duo.Side;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is a base class for actions in a {@link DecompilerDiffCodeComparisonPanel}
|
* This is a base class for actions in a {@link DecompilerCodeComparisonPanel}
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractMatchedTokensAction extends DockingAction {
|
public abstract class AbstractMatchedTokensAction extends DockingAction {
|
||||||
|
|
||||||
|
|
|
@ -15,150 +15,43 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.decompiler;
|
package ghidra.app.decompiler;
|
||||||
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
import ghidra.framework.options.SaveState;
|
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.listing.Program;
|
|
||||||
import ghidra.program.util.ProgramLocation;
|
import ghidra.program.util.ProgramLocation;
|
||||||
|
|
||||||
public class DecompilerLocation extends ProgramLocation {
|
/**
|
||||||
private Address functionEntryPoint;
|
* Represents a location in the Decompiler. This interface allows the Decompiler to subclass more
|
||||||
private DecompileResults results;
|
* general {@link ProgramLocation}s while adding more detailed Decompiler information.
|
||||||
private ClangToken token;
|
*/
|
||||||
private String tokenName;
|
public interface DecompilerLocation {
|
||||||
private int lineNumber;
|
|
||||||
private int charPos;
|
|
||||||
|
|
||||||
public DecompilerLocation(Program program, Address address, Address functionEntryPoint,
|
public Address getFunctionEntryPoint();
|
||||||
DecompileResults results, ClangToken token, int lineNumber, int charPos) {
|
|
||||||
super(program, address);
|
|
||||||
this.functionEntryPoint = functionEntryPoint;
|
|
||||||
this.results = results;
|
|
||||||
this.token = token;
|
|
||||||
this.tokenName = token.getText();
|
|
||||||
this.lineNumber = lineNumber;
|
|
||||||
this.charPos = charPos;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default constructor required for restoring a program location from XML.
|
|
||||||
*/
|
|
||||||
public DecompilerLocation() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public Address getFunctionEntryPoint() {
|
|
||||||
return functionEntryPoint;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Results from the decompilation
|
* Results from the decompilation
|
||||||
*
|
*
|
||||||
* @return C-AST, DFG, and CFG object. null if there are no results attached to this location
|
* @return C-AST, DFG, and CFG object. null if there are no results attached to this location
|
||||||
*/
|
*/
|
||||||
public DecompileResults getDecompile() {
|
public DecompileResults getDecompile();
|
||||||
return results;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* C text token at the current cursor location
|
* C text token at the current cursor location
|
||||||
*
|
*
|
||||||
* @return token at this location, could be null if there are no decompiler results
|
* @return token at this location, could be null if there are no decompiler results
|
||||||
*/
|
*/
|
||||||
public ClangToken getToken() {
|
public ClangToken getToken();
|
||||||
return token;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getTokenName() {
|
/**
|
||||||
return tokenName;
|
* {@return the name of the token for the current location}
|
||||||
}
|
*/
|
||||||
|
public String getTokenName();
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public int hashCode() {
|
* {@return the line number}
|
||||||
final int prime = 31;
|
*/
|
||||||
int result = super.hashCode();
|
public int getLineNumber();
|
||||||
result = prime * result + charPos;
|
|
||||||
result =
|
|
||||||
prime * result + ((functionEntryPoint == null) ? 0 : functionEntryPoint.hashCode());
|
|
||||||
result = prime * result + lineNumber;
|
|
||||||
result = prime * result + ((tokenName == null) ? 0 : tokenName.hashCode());
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public boolean equals(Object obj) {
|
* {@return the character position}
|
||||||
if (obj == null) {
|
*/
|
||||||
return false;
|
public int getCharPos();
|
||||||
}
|
|
||||||
if (this == obj) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (getClass() != obj.getClass()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!super.equals(obj)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
DecompilerLocation other = (DecompilerLocation) obj;
|
|
||||||
if (charPos != other.charPos) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lineNumber != other.lineNumber) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Objects.equals(functionEntryPoint, other.functionEntryPoint)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Objects.equals(tokenName, other.tokenName)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void saveState(SaveState saveState) {
|
|
||||||
super.saveState(saveState);
|
|
||||||
saveState.putString("_FUNCTION_ENTRY", functionEntryPoint.toString());
|
|
||||||
saveState.putString("_TOKEN_TEXT", tokenName);
|
|
||||||
saveState.putInt("_LINE_NUM", lineNumber);
|
|
||||||
saveState.putInt("_CHAR_POS", charPos);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void restoreState(Program program1, SaveState obj) {
|
|
||||||
super.restoreState(program1, obj);
|
|
||||||
String addrStr = obj.getString("_FUNCTION_ENTRY", "0");
|
|
||||||
functionEntryPoint = program1.parseAddress(addrStr)[0];
|
|
||||||
tokenName = obj.getString("_TOKEN_TEXT", "");
|
|
||||||
lineNumber = obj.getInt("_LINE_NUM", 0);
|
|
||||||
charPos = obj.getInt("_CHAR_POS", 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getLineNumber() {
|
|
||||||
return lineNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getCharPos() {
|
|
||||||
return charPos;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
StringBuilder buf = new StringBuilder();
|
|
||||||
buf.append(getClass().getSimpleName());
|
|
||||||
buf.append('@');
|
|
||||||
buf.append(addr.toString());
|
|
||||||
buf.append(", line=");
|
|
||||||
buf.append(lineNumber);
|
|
||||||
buf.append(", character=");
|
|
||||||
buf.append(charPos);
|
|
||||||
buf.append(", token=");
|
|
||||||
buf.append(tokenName);
|
|
||||||
return buf.toString();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,153 @@
|
||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.app.decompiler;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import ghidra.framework.options.SaveState;
|
||||||
|
import ghidra.program.model.address.Address;
|
||||||
|
import ghidra.program.model.listing.Program;
|
||||||
|
|
||||||
|
public class DecompilerLocationInfo {
|
||||||
|
|
||||||
|
private Address entryPoint;
|
||||||
|
private DecompileResults results;
|
||||||
|
private ClangToken token;
|
||||||
|
private String tokenName;
|
||||||
|
private int lineNumber;
|
||||||
|
private int charPos;
|
||||||
|
|
||||||
|
public DecompilerLocationInfo(Address entryPoint, DecompileResults results,
|
||||||
|
ClangToken token, int lineNumber, int charPos) {
|
||||||
|
this.entryPoint = entryPoint;
|
||||||
|
this.results = results;
|
||||||
|
this.token = token;
|
||||||
|
this.tokenName = token.getText();
|
||||||
|
this.lineNumber = lineNumber;
|
||||||
|
this.charPos = charPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default constructor required for restoring a program location from XML.
|
||||||
|
*/
|
||||||
|
public DecompilerLocationInfo() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Address getFunctionEntryPoint() {
|
||||||
|
return entryPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Results from the decompilation
|
||||||
|
*
|
||||||
|
* @return C-AST, DFG, and CFG object. null if there are no results attached to this location
|
||||||
|
*/
|
||||||
|
public DecompileResults getDecompile() {
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* C text token at the current cursor location
|
||||||
|
*
|
||||||
|
* @return token at this location, could be null if there are no decompiler results
|
||||||
|
*/
|
||||||
|
public ClangToken getToken() {
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTokenName() {
|
||||||
|
return tokenName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getLineNumber() {
|
||||||
|
return lineNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCharPos() {
|
||||||
|
return charPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
final int prime = 31;
|
||||||
|
int result = super.hashCode();
|
||||||
|
result = prime * result + charPos;
|
||||||
|
result =
|
||||||
|
prime * result + ((entryPoint == null) ? 0 : entryPoint.hashCode());
|
||||||
|
result = prime * result + lineNumber;
|
||||||
|
result = prime * result + ((tokenName == null) ? 0 : tokenName.hashCode());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (obj == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (getClass() != obj.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
DecompilerLocationInfo other = (DecompilerLocationInfo) obj;
|
||||||
|
if (charPos != other.charPos) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lineNumber != other.lineNumber) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Objects.equals(entryPoint, other.entryPoint)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Objects.equals(tokenName, other.tokenName)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void saveState(SaveState saveState) {
|
||||||
|
saveState.putString("_FUNCTION_ENTRY", entryPoint.toString());
|
||||||
|
saveState.putString("_TOKEN_TEXT", tokenName);
|
||||||
|
saveState.putInt("_LINE_NUM", lineNumber);
|
||||||
|
saveState.putInt("_CHAR_POS", charPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void restoreState(Program program1, SaveState obj) {
|
||||||
|
String addrStr = obj.getString("_FUNCTION_ENTRY", "0");
|
||||||
|
entryPoint = program1.parseAddress(addrStr)[0];
|
||||||
|
tokenName = obj.getString("_TOKEN_TEXT", "");
|
||||||
|
lineNumber = obj.getInt("_LINE_NUM", 0);
|
||||||
|
charPos = obj.getInt("_CHAR_POS", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
StringBuilder buf = new StringBuilder();
|
||||||
|
buf.append(getClass().getSimpleName());
|
||||||
|
buf.append(", line=");
|
||||||
|
buf.append(lineNumber);
|
||||||
|
buf.append(", character=");
|
||||||
|
buf.append(charPos);
|
||||||
|
buf.append(", token=");
|
||||||
|
buf.append(tokenName);
|
||||||
|
return buf.toString();
|
||||||
|
}
|
||||||
|
}
|
|
@ -41,13 +41,14 @@ import generic.theme.GColor;
|
||||||
import ghidra.app.decompiler.*;
|
import ghidra.app.decompiler.*;
|
||||||
import ghidra.app.decompiler.component.hover.DecompilerHoverService;
|
import ghidra.app.decompiler.component.hover.DecompilerHoverService;
|
||||||
import ghidra.app.decompiler.component.margin.*;
|
import ghidra.app.decompiler.component.margin.*;
|
||||||
|
import ghidra.app.decompiler.location.*;
|
||||||
import ghidra.app.plugin.core.decompile.DecompilerClipboardProvider;
|
import ghidra.app.plugin.core.decompile.DecompilerClipboardProvider;
|
||||||
import ghidra.app.plugin.core.decompile.actions.DecompilerSearchLocation;
|
import ghidra.app.plugin.core.decompile.actions.DecompilerSearchLocation;
|
||||||
import ghidra.app.util.viewer.util.ScrollpaneAlignedHorizontalLayout;
|
import ghidra.app.util.viewer.util.ScrollpaneAlignedHorizontalLayout;
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.listing.Function;
|
import ghidra.program.model.listing.*;
|
||||||
import ghidra.program.model.listing.Program;
|
|
||||||
import ghidra.program.model.pcode.*;
|
import ghidra.program.model.pcode.*;
|
||||||
|
import ghidra.program.model.symbol.Symbol;
|
||||||
import ghidra.program.util.ProgramLocation;
|
import ghidra.program.util.ProgramLocation;
|
||||||
import ghidra.program.util.ProgramSelection;
|
import ghidra.program.util.ProgramSelection;
|
||||||
import ghidra.util.*;
|
import ghidra.util.*;
|
||||||
|
@ -979,17 +980,103 @@ public class DecompilerPanel extends JPanel implements FieldMouseListener, Field
|
||||||
if (token == null) {
|
if (token == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Address address = DecompilerUtils.getClosestAddress(getProgram(), token);
|
Address address = DecompilerUtils.getClosestAddress(getProgram(), token);
|
||||||
if (address == null) {
|
if (address == null) {
|
||||||
address = DecompilerUtils.findAddressBefore(layoutController.getFields(), token);
|
address = DecompilerUtils.findAddressBefore(layoutController.getFields(), token);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Function function = decompileData.getFunction();
|
||||||
if (address == null) {
|
if (address == null) {
|
||||||
address = decompileData.getFunction().getEntryPoint();
|
address = function.getEntryPoint();
|
||||||
}
|
}
|
||||||
|
|
||||||
return new DecompilerLocation(decompileData.getProgram(), address,
|
Address entryPoint = function.getEntryPoint();
|
||||||
decompileData.getFunction().getEntryPoint(), decompileData.getDecompileResults(), token,
|
DecompileResults results = decompileData.getDecompileResults();
|
||||||
location.getIndex().intValue(), location.col);
|
int lineNumber = location.getIndex().intValue();
|
||||||
|
int charPos = location.col;
|
||||||
|
DecompilerLocationInfo info =
|
||||||
|
new DecompilerLocationInfo(entryPoint, results, token, lineNumber, charPos);
|
||||||
|
Program program = decompileData.getProgram();
|
||||||
|
ProgramLocation signatureLocation = createFunctionSignatureLocation(token, address, info);
|
||||||
|
if (signatureLocation != null) {
|
||||||
|
return signatureLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new DefaultDecompilerLocation(program, address, info);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ProgramLocation createFunctionSignatureLocation(ClangToken token, Address address,
|
||||||
|
DecompilerLocationInfo info) {
|
||||||
|
|
||||||
|
Function function = decompileData.getFunction();
|
||||||
|
Address entryPoint = function.getEntryPoint();
|
||||||
|
if (!entryPoint.equals(address)) {
|
||||||
|
// Another address implies that we are not on the function signature
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (token instanceof ClangFuncNameToken ft) {
|
||||||
|
// if the token address is the entry point of this function, then create a location that
|
||||||
|
// will place the cursor on the function signature in the listing
|
||||||
|
Program program = decompileData.getProgram();
|
||||||
|
String functionName = ft.getText();
|
||||||
|
return new FunctionNameDecompilerLocation(program, entryPoint, functionName, info);
|
||||||
|
}
|
||||||
|
else if (token instanceof ClangVariableToken cvt) {
|
||||||
|
return createVariableDeclarationLocation(cvt, address, info);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ProgramLocation createVariableDeclarationLocation(ClangVariableToken cvt,
|
||||||
|
Address address, DecompilerLocationInfo info) {
|
||||||
|
|
||||||
|
Function function = decompileData.getFunction();
|
||||||
|
Address entryPoint = function.getEntryPoint();
|
||||||
|
Program program = decompileData.getProgram();
|
||||||
|
Variable variable = getVariable(cvt);
|
||||||
|
if (variable != null) {
|
||||||
|
return new VariableDecompilerLocation(program, entryPoint, variable, info);
|
||||||
|
}
|
||||||
|
|
||||||
|
HighVariable highVar = cvt.getHighVariable();
|
||||||
|
if (highVar == null) {
|
||||||
|
// decomp param that is not in the listing; put on signature
|
||||||
|
return new FunctionNameDecompilerLocation(program, entryPoint, cvt.getText(), info);
|
||||||
|
}
|
||||||
|
|
||||||
|
HighSymbol highSymbol = highVar.getSymbol();
|
||||||
|
if (highSymbol.isParameter()) {
|
||||||
|
// decomp param that is not in the listing; put on signature
|
||||||
|
return new FunctionNameDecompilerLocation(program, entryPoint, cvt.getText(), info);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Variable getVariable(ClangVariableToken token) {
|
||||||
|
|
||||||
|
HighVariable highVar = token.getHighVariable();
|
||||||
|
if (highVar == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
HighSymbol highSymbol = highVar.getSymbol();
|
||||||
|
Variable variable = HighFunctionDBUtil.getFunctionVariable(highSymbol);
|
||||||
|
if (variable != null) {
|
||||||
|
return variable;
|
||||||
|
}
|
||||||
|
|
||||||
|
Function function = decompileData.getFunction();
|
||||||
|
Symbol symbol = highSymbol.getSymbol();
|
||||||
|
Variable[] locals = function.getLocalVariables();
|
||||||
|
for (Variable local : locals) {
|
||||||
|
Symbol localSymbol = local.getSymbol();
|
||||||
|
if (symbol == localSymbol) {
|
||||||
|
return local;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSearchResults(SearchLocation searchLocation) {
|
public void setSearchResults(SearchLocation searchLocation) {
|
||||||
|
|
|
@ -0,0 +1,113 @@
|
||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.app.decompiler.location;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import ghidra.app.decompiler.*;
|
||||||
|
import ghidra.framework.options.SaveState;
|
||||||
|
import ghidra.program.model.address.Address;
|
||||||
|
import ghidra.program.model.listing.Program;
|
||||||
|
import ghidra.program.util.ProgramLocation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default location handed out when the user clicks inside of the Decompiler.
|
||||||
|
*/
|
||||||
|
public class DefaultDecompilerLocation extends ProgramLocation implements DecompilerLocation {
|
||||||
|
|
||||||
|
private DecompilerLocationInfo info;
|
||||||
|
|
||||||
|
public DefaultDecompilerLocation(Program program, Address address,
|
||||||
|
DecompilerLocationInfo info) {
|
||||||
|
super(program, address);
|
||||||
|
|
||||||
|
this.info = info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DefaultDecompilerLocation() {
|
||||||
|
// for restoring from xml
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Address getFunctionEntryPoint() {
|
||||||
|
return info.getFunctionEntryPoint();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DecompileResults getDecompile() {
|
||||||
|
return info.getDecompile();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ClangToken getToken() {
|
||||||
|
return info.getToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getTokenName() {
|
||||||
|
return info.getTokenName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getLineNumber() {
|
||||||
|
return info.getLineNumber();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getCharPos() {
|
||||||
|
return info.getCharPos();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void saveState(SaveState ss) {
|
||||||
|
super.saveState(ss);
|
||||||
|
info.saveState(ss);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void restoreState(Program p, SaveState ss) {
|
||||||
|
super.restoreState(p, ss);
|
||||||
|
info.restoreState(p, ss);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int result = super.hashCode();
|
||||||
|
result = info.hashCode();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (obj == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (getClass() != obj.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!super.equals(obj)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
DefaultDecompilerLocation other = (DefaultDecompilerLocation) obj;
|
||||||
|
return Objects.equals(info, other.info);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,108 @@
|
||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.app.decompiler.location;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import ghidra.app.decompiler.*;
|
||||||
|
import ghidra.framework.options.SaveState;
|
||||||
|
import ghidra.program.model.address.Address;
|
||||||
|
import ghidra.program.model.listing.Program;
|
||||||
|
import ghidra.program.util.FunctionNameFieldLocation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A location created when a function name is clicked in the Decompiler.
|
||||||
|
*/
|
||||||
|
public class FunctionNameDecompilerLocation extends FunctionNameFieldLocation
|
||||||
|
implements DecompilerLocation {
|
||||||
|
|
||||||
|
private DecompilerLocationInfo info;
|
||||||
|
|
||||||
|
public FunctionNameDecompilerLocation(Program program, Address address, String funcionName,
|
||||||
|
DecompilerLocationInfo info) {
|
||||||
|
super(program, address, funcionName);
|
||||||
|
this.info = info;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Address getFunctionEntryPoint() {
|
||||||
|
return info.getFunctionEntryPoint();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DecompileResults getDecompile() {
|
||||||
|
return info.getDecompile();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ClangToken getToken() {
|
||||||
|
return info.getToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getTokenName() {
|
||||||
|
return info.getTokenName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getLineNumber() {
|
||||||
|
return info.getLineNumber();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getCharPos() {
|
||||||
|
return info.getCharPos();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void saveState(SaveState ss) {
|
||||||
|
super.saveState(ss);
|
||||||
|
info.saveState(ss);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void restoreState(Program p, SaveState ss) {
|
||||||
|
super.restoreState(p, ss);
|
||||||
|
info.restoreState(p, ss);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int result = super.hashCode();
|
||||||
|
result = info.hashCode();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (obj == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (getClass() != obj.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!super.equals(obj)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
FunctionNameDecompilerLocation other = (FunctionNameDecompilerLocation) obj;
|
||||||
|
return Objects.equals(info, other.info);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,109 @@
|
||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.app.decompiler.location;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import ghidra.app.decompiler.*;
|
||||||
|
import ghidra.framework.options.SaveState;
|
||||||
|
import ghidra.program.model.address.Address;
|
||||||
|
import ghidra.program.model.listing.Program;
|
||||||
|
import ghidra.program.model.listing.Variable;
|
||||||
|
import ghidra.program.util.VariableLocFieldLocation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A location created when a function variable is clicked in the Decompiler.
|
||||||
|
*/
|
||||||
|
public class VariableDecompilerLocation extends VariableLocFieldLocation
|
||||||
|
implements DecompilerLocation {
|
||||||
|
|
||||||
|
private DecompilerLocationInfo info;
|
||||||
|
|
||||||
|
public VariableDecompilerLocation(Program program, Address locationAddr, Variable var,
|
||||||
|
DecompilerLocationInfo info) {
|
||||||
|
super(program, locationAddr, var, 0);
|
||||||
|
this.info = info;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Address getFunctionEntryPoint() {
|
||||||
|
return info.getFunctionEntryPoint();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DecompileResults getDecompile() {
|
||||||
|
return info.getDecompile();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ClangToken getToken() {
|
||||||
|
return info.getToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getTokenName() {
|
||||||
|
return info.getTokenName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getLineNumber() {
|
||||||
|
return info.getLineNumber();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getCharPos() {
|
||||||
|
return info.getCharPos();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void saveState(SaveState ss) {
|
||||||
|
super.saveState(ss);
|
||||||
|
info.saveState(ss);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void restoreState(Program p, SaveState ss) {
|
||||||
|
super.restoreState(p, ss);
|
||||||
|
info.restoreState(p, ss);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int result = super.hashCode();
|
||||||
|
result = info.hashCode();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (obj == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (getClass() != obj.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!super.equals(obj)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
VariableDecompilerLocation other = (VariableDecompilerLocation) obj;
|
||||||
|
return Objects.equals(info, other.info);
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,8 +17,7 @@ package ghidra.app.plugin.core.decompile;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
import java.util.function.BooleanSupplier;
|
import java.util.function.*;
|
||||||
import java.util.function.Supplier;
|
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
@ -34,10 +33,11 @@ import ghidra.app.plugin.core.navigation.NextPrevAddressPlugin;
|
||||||
import ghidra.app.services.GoToService;
|
import ghidra.app.services.GoToService;
|
||||||
import ghidra.app.util.navigation.GoToServiceImpl;
|
import ghidra.app.util.navigation.GoToServiceImpl;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.listing.*;
|
import ghidra.program.model.listing.Function;
|
||||||
|
import ghidra.program.model.listing.Library;
|
||||||
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.program.model.symbol.*;
|
import ghidra.program.model.symbol.*;
|
||||||
import ghidra.program.util.OperandFieldLocation;
|
import ghidra.program.util.*;
|
||||||
import ghidra.program.util.ProgramLocation;
|
|
||||||
import ghidra.test.ClassicSampleX86ProgramBuilder;
|
import ghidra.test.ClassicSampleX86ProgramBuilder;
|
||||||
|
|
||||||
public class DecompilerNavigationTest extends AbstractDecompilerTest {
|
public class DecompilerNavigationTest extends AbstractDecompilerTest {
|
||||||
|
@ -77,7 +77,7 @@ public class DecompilerNavigationTest extends AbstractDecompilerTest {
|
||||||
|
|
||||||
private Program buildProgram() throws Exception {
|
private Program buildProgram() throws Exception {
|
||||||
ClassicSampleX86ProgramBuilder builder =
|
ClassicSampleX86ProgramBuilder builder =
|
||||||
new ClassicSampleX86ProgramBuilder("notepad", false, this);
|
new ClassicSampleX86ProgramBuilder("sample", false, this);
|
||||||
|
|
||||||
// need a default label at 01002cf0, so make up a reference
|
// need a default label at 01002cf0, so make up a reference
|
||||||
builder.createMemoryReference("01002ce5", "01002cf0", RefType.FALL_THROUGH,
|
builder.createMemoryReference("01002ce5", "01002cf0", RefType.FALL_THROUGH,
|
||||||
|
@ -230,6 +230,111 @@ public class DecompilerNavigationTest extends AbstractDecompilerTest {
|
||||||
assertCurrentAddress(f1);
|
assertCurrentAddress(f1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDecompilerLocationEvent_VariableDeclaration() {
|
||||||
|
|
||||||
|
/*
|
||||||
|
undefined4 FUN_010059a3(undefined4 param_1,undefined4 param_2,int param_3)
|
||||||
|
|
||||||
|
{
|
||||||
|
int iVar1;
|
||||||
|
int iVar2;
|
||||||
|
int *piVar3;
|
||||||
|
undefined4 uVar4;
|
||||||
|
int iVar5;
|
||||||
|
bool bVar6;
|
||||||
|
int local_14;
|
||||||
|
int local_10;
|
||||||
|
undefined1 local_c [4];
|
||||||
|
undefined4 local_8;
|
||||||
|
*/
|
||||||
|
|
||||||
|
decompile("010059a3"); // FUN_010059a3
|
||||||
|
|
||||||
|
// 16: undefined4 local_8;
|
||||||
|
int line = 16;
|
||||||
|
int character = 13;
|
||||||
|
assertToken("local_8", line, character);
|
||||||
|
setDecompilerLocation(line, character);
|
||||||
|
|
||||||
|
assertLocationType(loc -> loc instanceof VariableLocFieldLocation);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDecompilerLocationEvent_FunctionSignature_Parameter() {
|
||||||
|
|
||||||
|
/*
|
||||||
|
undefined4 FUN_010059a3(undefined4 param_1,undefined4 param_2,int param_3)
|
||||||
|
|
||||||
|
{
|
||||||
|
int iVar1;
|
||||||
|
int iVar2;
|
||||||
|
int *piVar3;
|
||||||
|
undefined4 uVar4;
|
||||||
|
int iVar5;
|
||||||
|
bool bVar6;
|
||||||
|
int local_14;
|
||||||
|
int local_10;
|
||||||
|
undefined1 local_c [4];
|
||||||
|
undefined4 local_8;
|
||||||
|
*/
|
||||||
|
|
||||||
|
decompile("010059a3"); // FUN_010059a3
|
||||||
|
|
||||||
|
// 4: undefined4 FUN_010059a3(undefined4 param_1
|
||||||
|
int line = 4;
|
||||||
|
int character = 36;
|
||||||
|
assertToken("param_1", line, character);
|
||||||
|
setDecompilerLocation(line, character);
|
||||||
|
|
||||||
|
assertLocationType(loc -> loc instanceof VariableLocFieldLocation);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDecompilerLocationEvent_FunctionSignature_FunctionName() {
|
||||||
|
|
||||||
|
/*
|
||||||
|
undefined4 FUN_010059a3(undefined4 param_1,undefined4 param_2,int param_3)
|
||||||
|
|
||||||
|
{
|
||||||
|
int iVar1;
|
||||||
|
int iVar2;
|
||||||
|
int *piVar3;
|
||||||
|
undefined4 uVar4;
|
||||||
|
int iVar5;
|
||||||
|
bool bVar6;
|
||||||
|
int local_14;
|
||||||
|
int local_10;
|
||||||
|
undefined1 local_c [4];
|
||||||
|
undefined4 local_8;
|
||||||
|
*/
|
||||||
|
|
||||||
|
decompile("010059a3"); // FUN_010059a3
|
||||||
|
|
||||||
|
// 4: undefined4 FUN_010059a3(undefined4 param_1
|
||||||
|
int line = 4;
|
||||||
|
int character = 12;
|
||||||
|
assertToken("FUN_010059a3", line, character);
|
||||||
|
setDecompilerLocation(line, character);
|
||||||
|
|
||||||
|
assertLocationType(loc -> loc instanceof FunctionNameFieldLocation);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertLocationType(Predicate<ProgramLocation> predicate) {
|
||||||
|
waitForSwing();
|
||||||
|
|
||||||
|
BooleanSupplier success = () -> {
|
||||||
|
ProgramLocation loc = codeBrowser.getCurrentLocation();
|
||||||
|
return predicate.test(loc);
|
||||||
|
};
|
||||||
|
|
||||||
|
Supplier<String> failureMessage =
|
||||||
|
() -> "Listing is not at the expected field location. Current location: " +
|
||||||
|
codeBrowser.getCurrentLocation();
|
||||||
|
|
||||||
|
waitForCondition(success, failureMessage);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void assertCurrentAddress(Address expected) {
|
public void assertCurrentAddress(Address expected) {
|
||||||
codeBrowser.updateNow();
|
codeBrowser.updateNow();
|
||||||
|
|
|
@ -19,12 +19,10 @@ import db.DBRecord;
|
||||||
import ghidra.program.database.DBObjectCache;
|
import ghidra.program.database.DBObjectCache;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.symbol.*;
|
import ghidra.program.model.symbol.*;
|
||||||
import ghidra.program.util.ProgramLocation;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Symbols that represent "classes"
|
* Symbols that represent classes
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class ClassSymbol extends SymbolDB {
|
public class ClassSymbol extends SymbolDB {
|
||||||
|
|
||||||
private GhidraClassDB ghidraClass;
|
private GhidraClassDB ghidraClass;
|
||||||
|
@ -42,17 +40,11 @@ public class ClassSymbol extends SymbolDB {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.symbol.Symbol#getSymbolType()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public SymbolType getSymbolType() {
|
public SymbolType getSymbolType() {
|
||||||
return SymbolType.CLASS;
|
return SymbolType.CLASS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.symbol.Symbol#getObject()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public Object getObject() {
|
public Object getObject() {
|
||||||
lock.acquire();
|
lock.acquire();
|
||||||
|
@ -68,9 +60,6 @@ public class ClassSymbol extends SymbolDB {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.symbol.Symbol#isPrimary()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isPrimary() {
|
public boolean isPrimary() {
|
||||||
return true;
|
return true;
|
||||||
|
@ -82,17 +71,6 @@ public class ClassSymbol extends SymbolDB {
|
||||||
return parentSymbol != null ? parentSymbol.isExternal() : false;
|
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
|
@Override
|
||||||
public boolean isValidParent(Namespace parent) {
|
public boolean isValidParent(Namespace parent) {
|
||||||
return super.isValidParent(parent) &&
|
return super.isValidParent(parent) &&
|
||||||
|
|
|
@ -32,7 +32,6 @@ import ghidra.program.util.ProgramLocation;
|
||||||
* EXTERNAL:
|
* EXTERNAL:
|
||||||
* String stringData - external memory address/label
|
* String stringData - external memory address/label
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class CodeSymbol extends SymbolDB {
|
public class CodeSymbol extends SymbolDB {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -58,9 +57,6 @@ public class CodeSymbol extends SymbolDB {
|
||||||
super(mgr, cache, addr, key);
|
super(mgr, cache, addr, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.symbol.Symbol#getSymbolType()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public SymbolType getSymbolType() {
|
public SymbolType getSymbolType() {
|
||||||
return SymbolType.LABEL;
|
return SymbolType.LABEL;
|
||||||
|
@ -124,9 +120,6 @@ public class CodeSymbol extends SymbolDB {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.symbol.Symbol#getObject()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public Object getObject() {
|
public Object getObject() {
|
||||||
lock.acquire();
|
lock.acquire();
|
||||||
|
@ -155,9 +148,6 @@ public class CodeSymbol extends SymbolDB {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.symbol.Symbol#isPrimary()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isPrimary() {
|
public boolean isPrimary() {
|
||||||
if (getSource() == SourceType.DEFAULT || isExternal()) {
|
if (getSource() == SourceType.DEFAULT || isExternal()) {
|
||||||
|
@ -166,9 +156,6 @@ public class CodeSymbol extends SymbolDB {
|
||||||
return doCheckIsPrimary();
|
return doCheckIsPrimary();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.symbol.Symbol#setPrimary()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public boolean setPrimary() {
|
public boolean setPrimary() {
|
||||||
lock.acquire();
|
lock.acquire();
|
||||||
|
@ -205,17 +192,11 @@ public class CodeSymbol extends SymbolDB {
|
||||||
doSetPrimary(primary);
|
doSetPrimary(primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.symbol.Symbol#getProgramLocation()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public ProgramLocation getProgramLocation() {
|
public ProgramLocation getProgramLocation() {
|
||||||
return new LabelFieldLocation(this);
|
return new LabelFieldLocation(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.symbol.Symbol#isValidParent(ghidra.program.model.symbol.Namespace)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isValidParent(Namespace parent) {
|
public boolean isValidParent(Namespace parent) {
|
||||||
return super.isValidParent(parent) &&
|
return super.isValidParent(parent) &&
|
||||||
|
|
|
@ -57,9 +57,6 @@ public class FunctionSymbol extends SymbolDB {
|
||||||
this.functionMgr = symbolMgr.getFunctionManager();
|
this.functionMgr = symbolMgr.getFunctionManager();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.symbol.Symbol#getSymbolType()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public SymbolType getSymbolType() {
|
public SymbolType getSymbolType() {
|
||||||
return SymbolType.FUNCTION;
|
return SymbolType.FUNCTION;
|
||||||
|
|
|
@ -22,7 +22,6 @@ import ghidra.program.model.listing.CircularDependencyException;
|
||||||
import ghidra.program.model.listing.Library;
|
import ghidra.program.model.listing.Library;
|
||||||
import ghidra.program.model.symbol.*;
|
import ghidra.program.model.symbol.*;
|
||||||
import ghidra.program.util.ProgramEvent;
|
import ghidra.program.util.ProgramEvent;
|
||||||
import ghidra.program.util.ProgramLocation;
|
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
import ghidra.util.exception.DuplicateNameException;
|
import ghidra.util.exception.DuplicateNameException;
|
||||||
import ghidra.util.exception.InvalidInputException;
|
import ghidra.util.exception.InvalidInputException;
|
||||||
|
@ -33,7 +32,6 @@ import ghidra.util.exception.InvalidInputException;
|
||||||
* Symbol data usage:
|
* Symbol data usage:
|
||||||
* String stringData - associated program project file path
|
* String stringData - associated program project file path
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class LibrarySymbol extends SymbolDB {
|
public class LibrarySymbol extends SymbolDB {
|
||||||
|
|
||||||
private LibraryDB library;
|
private LibraryDB library;
|
||||||
|
@ -93,6 +91,7 @@ public class LibrarySymbol extends SymbolDB {
|
||||||
.setObjChanged(ProgramEvent.EXTERNAL_PATH_CHANGED, getName(), oldPath, newPath);
|
.setObjChanged(ProgramEvent.EXTERNAL_PATH_CHANGED, getName(), oldPath, newPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public SymbolType getSymbolType() {
|
public SymbolType getSymbolType() {
|
||||||
return SymbolType.LIBRARY;
|
return SymbolType.LIBRARY;
|
||||||
}
|
}
|
||||||
|
@ -115,14 +114,6 @@ public class LibrarySymbol extends SymbolDB {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.symbol.Symbol#getProgramLocation()
|
|
||||||
*/
|
|
||||||
public ProgramLocation getProgramLocation() {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isValidParent(Namespace parent) {
|
public boolean isValidParent(Namespace parent) {
|
||||||
return super.isValidParent(parent) &&
|
return super.isValidParent(parent) &&
|
||||||
|
|
|
@ -19,15 +19,13 @@ import db.DBRecord;
|
||||||
import ghidra.program.database.DBObjectCache;
|
import ghidra.program.database.DBObjectCache;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.symbol.*;
|
import ghidra.program.model.symbol.*;
|
||||||
import ghidra.program.util.ProgramLocation;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Symbol class for namespaces.
|
* Symbol class for namespaces.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class NamespaceSymbol extends SymbolDB {
|
public class NamespaceSymbol extends SymbolDB {
|
||||||
|
|
||||||
NamespaceDB namespace;
|
private NamespaceDB namespace;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new namespace symbol
|
* Construct a new namespace symbol
|
||||||
|
@ -36,13 +34,11 @@ public class NamespaceSymbol extends SymbolDB {
|
||||||
* @param addr the address for this symbol.
|
* @param addr the address for this symbol.
|
||||||
* @param record the record 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);
|
super(mgr, cache, addr, record);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.database.symbol.SymbolDB#isPrimary()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isPrimary() {
|
public boolean isPrimary() {
|
||||||
return true;
|
return true;
|
||||||
|
@ -54,25 +50,11 @@ public class NamespaceSymbol extends SymbolDB {
|
||||||
return parentSymbol != null ? parentSymbol.isExternal() : false;
|
return parentSymbol != null ? parentSymbol.isExternal() : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.symbol.Symbol#getSymbolType()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public SymbolType getSymbolType() {
|
public SymbolType getSymbolType() {
|
||||||
return SymbolType.NAMESPACE;
|
return SymbolType.NAMESPACE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.symbol.Symbol#getProgramLocation()
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public ProgramLocation getProgramLocation() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.symbol.Symbol#getObject()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public Object getObject() {
|
public Object getObject() {
|
||||||
return getNamespace();
|
return getNamespace();
|
||||||
|
@ -85,9 +67,6 @@ public class NamespaceSymbol extends SymbolDB {
|
||||||
return namespace;
|
return namespace;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.symbol.Symbol#isValidParent(ghidra.program.model.symbol.Namespace)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isValidParent(Namespace parent) {
|
public boolean isValidParent(Namespace parent) {
|
||||||
// TODO: Not sure what other constraints should be placed on namespace movement
|
// TODO: Not sure what other constraints should be placed on namespace movement
|
||||||
|
|
|
@ -100,9 +100,6 @@ public class VariableSymbolDB extends SymbolDB {
|
||||||
return variableStorage;
|
return variableStorage;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.symbol.Symbol#getSymbolType()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public SymbolType getSymbolType() {
|
public SymbolType getSymbolType() {
|
||||||
return type;
|
return type;
|
||||||
|
@ -115,18 +112,12 @@ public class VariableSymbolDB extends SymbolDB {
|
||||||
return isValid;
|
return isValid;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.database.symbol.SymbolDB#equals(java.lang.Object)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object obj) {
|
public boolean equals(Object obj) {
|
||||||
// TODO: not sure what constitutes equality since address will differ
|
// TODO: not sure what constitutes equality since address will differ
|
||||||
return obj == this;
|
return obj == this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.symbol.Symbol#delete()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public boolean delete() {
|
public boolean delete() {
|
||||||
lock.acquire();
|
lock.acquire();
|
||||||
|
@ -146,9 +137,6 @@ public class VariableSymbolDB extends SymbolDB {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.symbol.Symbol#getObject()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public Object getObject() {
|
public Object getObject() {
|
||||||
FunctionDB func = getFunction();
|
FunctionDB func = getFunction();
|
||||||
|
@ -158,9 +146,6 @@ public class VariableSymbolDB extends SymbolDB {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.symbol.Symbol#isPrimary()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isPrimary() {
|
public boolean isPrimary() {
|
||||||
return false;
|
return false;
|
||||||
|
@ -178,9 +163,6 @@ public class VariableSymbolDB extends SymbolDB {
|
||||||
getParentNamespace().getID());
|
getParentNamespace().getID());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.symbol.Symbol#getProgramLocation()
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public ProgramLocation getProgramLocation() {
|
public ProgramLocation getProgramLocation() {
|
||||||
Variable var = (Variable) getObject();
|
Variable var = (Variable) getObject();
|
||||||
|
@ -190,9 +172,6 @@ public class VariableSymbolDB extends SymbolDB {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ghidra.program.model.symbol.Symbol#isValidParent(ghidra.program.model.symbol.Namespace)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isValidParent(Namespace parent) {
|
public boolean isValidParent(Namespace parent) {
|
||||||
// symbol is locked to single function and can't be moved
|
// 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
|
* Change the storage address and data-type associated with this variable symbol.
|
||||||
* variable symbol.
|
* @param newStorage the new storage
|
||||||
* @param newStorage
|
|
||||||
* @param dt data-type
|
* @param dt data-type
|
||||||
*/
|
*/
|
||||||
public void setStorageAndDataType(VariableStorage newStorage, DataType dt) {
|
public void setStorageAndDataType(VariableStorage newStorage, DataType dt) {
|
||||||
|
|
|
@ -18,7 +18,6 @@ package ghidra.program.model.address;
|
||||||
import ghidra.program.model.listing.CircularDependencyException;
|
import ghidra.program.model.listing.CircularDependencyException;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.program.model.symbol.*;
|
import ghidra.program.model.symbol.*;
|
||||||
import ghidra.program.util.ProgramLocation;
|
|
||||||
import ghidra.util.exception.DuplicateNameException;
|
import ghidra.util.exception.DuplicateNameException;
|
||||||
import ghidra.util.exception.InvalidInputException;
|
import ghidra.util.exception.InvalidInputException;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
@ -140,11 +139,6 @@ public class GlobalSymbol implements Symbol {
|
||||||
return new Reference[0];
|
return new Reference[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public ProgramLocation getProgramLocation() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setName(String newName, SourceType source)
|
public void setName(String newName, SourceType source)
|
||||||
throws DuplicateNameException, InvalidInputException {
|
throws DuplicateNameException, InvalidInputException {
|
||||||
|
|
|
@ -385,6 +385,44 @@ public class HighFunctionDBUtil {
|
||||||
return res;
|
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
|
* Low-level routine for clearing any variables in the
|
||||||
* database which conflict with this variable and return
|
* database which conflict with this variable and return
|
||||||
|
@ -477,6 +515,38 @@ public class HighFunctionDBUtil {
|
||||||
return parameters[slot];
|
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
|
* Rename and/or retype the specified variable in the database. All parameters may be flushed
|
||||||
* to the database if typed parameter inconsistency detected.
|
* to the database if typed parameter inconsistency detected.
|
||||||
|
|
|
@ -128,9 +128,14 @@ public interface Symbol {
|
||||||
public Reference[] getReferences();
|
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.
|
* Sets the name this symbol.
|
||||||
|
|
|
@ -38,7 +38,7 @@ public class FunctionLocation extends ProgramLocation {
|
||||||
* @param functionAddr the function address
|
* @param functionAddr the function address
|
||||||
* @param row the row in the field
|
* @param row the row in the field
|
||||||
* @param col the display piece on the row
|
* @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,
|
protected FunctionLocation(Program program, Address locationAddr, Address functionAddr, int row,
|
||||||
int col, int charOffset) {
|
int col, int charOffset) {
|
||||||
|
@ -53,9 +53,6 @@ public class FunctionLocation extends ProgramLocation {
|
||||||
protected FunctionLocation() {
|
protected FunctionLocation() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see java.lang.Object#equals(java.lang.Object)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object obj) {
|
public boolean equals(Object obj) {
|
||||||
if (super.equals(obj)) {
|
if (super.equals(obj)) {
|
||||||
|
|
|
@ -25,18 +25,16 @@ import ghidra.program.model.listing.Program;
|
||||||
import ghidra.program.model.symbol.*;
|
import ghidra.program.model.symbol.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The <CODE>LableFieldLocation</CODE> class contains specific location information
|
* This class contains specific location information within the label field of a
|
||||||
* within the LABEL field of a CodeUnitLocation object.
|
* {@link CodeUnitLocation}
|
||||||
*/
|
*/
|
||||||
public class LabelFieldLocation extends CodeUnitLocation {
|
public class LabelFieldLocation extends CodeUnitLocation {
|
||||||
private SymbolPath symbolPath;
|
private SymbolPath symbolPath;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default constructor needed for restoring
|
* Default constructor needed for restoring a label field location from XML
|
||||||
* a label field location from XML
|
|
||||||
*/
|
*/
|
||||||
public LabelFieldLocation() {
|
public LabelFieldLocation() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -45,8 +43,9 @@ public class LabelFieldLocation extends CodeUnitLocation {
|
||||||
* @param program the program of the location
|
* @param program the program of the location
|
||||||
* @param addr address of the location; should not be null
|
* @param addr address of the location; should not be null
|
||||||
* @param componentPath array of indexes for each nested data component; the
|
* @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 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
|
* @param row the row in list of labels as displayed by the label field. Only used for
|
||||||
* program location comparison purposes.
|
* program location comparison purposes.
|
||||||
* @param charOffset the column position within the label string for this location.
|
* @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() {
|
public String getName() {
|
||||||
return symbolPath.getName();
|
return symbolPath.getName();
|
||||||
}
|
}
|
||||||
|
@ -143,9 +139,6 @@ public class LabelFieldLocation extends CodeUnitLocation {
|
||||||
return symbolPath;
|
return symbolPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a String representation of this location.
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return super.toString() + ", Label = " + symbolPath.getPath();
|
return super.toString() + ", Label = " + symbolPath.getPath();
|
||||||
|
|
|
@ -48,6 +48,7 @@ public class ProgramLocation implements Cloneable, Comparable<ProgramLocation> {
|
||||||
private int row;
|
private int row;
|
||||||
private int col;
|
private int col;
|
||||||
private int charOffset;
|
private int charOffset;
|
||||||
|
private boolean hasBeenRestored;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new ProgramLocation.
|
* 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.
|
* 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
|
* @param obj the save state to restore from
|
||||||
*/
|
*/
|
||||||
public void restoreState(Program program1, SaveState obj) {
|
public void restoreState(Program newProgram, SaveState obj) {
|
||||||
this.program = program1;
|
|
||||||
|
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 addrStr = obj.getString("_ADDRESS", "0");
|
||||||
String byteAddrStr = obj.getString("_BYTE_ADDR", addrStr);
|
String byteAddrStr = obj.getString("_BYTE_ADDR", addrStr);
|
||||||
String refAddrStr = obj.getString("_REF_ADDRESS", null);
|
String refAddrStr = obj.getString("_REF_ADDRESS", null);
|
||||||
componentPath = obj.getInts("_COMP_PATH", null);
|
componentPath = obj.getInts("_COMP_PATH", null);
|
||||||
addr = ProgramUtilities.parseAddress(program1, addrStr);
|
addr = ProgramUtilities.parseAddress(program, addrStr);
|
||||||
byteAddr = ProgramUtilities.parseAddress(program1, byteAddrStr);
|
byteAddr = ProgramUtilities.parseAddress(program, byteAddrStr);
|
||||||
if (refAddrStr != null) {
|
if (refAddrStr != null) {
|
||||||
refAddr = ProgramUtilities.parseAddress(program1, refAddrStr);
|
refAddr = ProgramUtilities.parseAddress(program, refAddrStr);
|
||||||
}
|
}
|
||||||
col = obj.getInt("_COLUMN", 0);
|
col = obj.getInt("_COLUMN", 0);
|
||||||
row = obj.getInt("_ROW", 0);
|
row = obj.getInt("_ROW", 0);
|
||||||
charOffset = obj.getInt("_CHAR_OFFSET", 0);
|
charOffset = obj.getInt("_CHAR_OFFSET", 0);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -271,18 +279,24 @@ public class ProgramLocation implements Cloneable, Comparable<ProgramLocation> {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Class<?> locClass = Class.forName(className);
|
Class<?> locationClass = Class.forName(className);
|
||||||
ProgramLocation loc = (ProgramLocation) locClass.getConstructor().newInstance();
|
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);
|
loc.restoreState(program, saveState);
|
||||||
if (loc.getAddress() != null) {
|
if (loc.getAddress() != null) {
|
||||||
return loc;
|
return loc;
|
||||||
}
|
}
|
||||||
// no address, it must be in a removed block; we can't use it
|
// 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) {
|
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) {
|
catch (InstantiationException | IllegalAccessException | NoSuchMethodException e) {
|
||||||
Msg.showError(ProgramLocation.class, null, "Programming Error",
|
Msg.showError(ProgramLocation.class, null, "Programming Error",
|
||||||
|
|
|
@ -68,6 +68,7 @@ public class VariableLocFieldLocation extends VariableLocation {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the location string. (For stack variables this is the offset as a string.)
|
* Gets the location string. (For stack variables this is the offset as a string.)
|
||||||
|
* @return the location string
|
||||||
*/
|
*/
|
||||||
public String getLoc() {
|
public String getLoc() {
|
||||||
return loc;
|
return loc;
|
||||||
|
@ -83,19 +84,24 @@ public class VariableLocFieldLocation extends VariableLocation {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object obj) {
|
public boolean equals(Object obj) {
|
||||||
if (this == obj)
|
if (this == obj) {
|
||||||
return true;
|
return true;
|
||||||
if (!super.equals(obj))
|
}
|
||||||
|
if (!super.equals(obj)) {
|
||||||
return false;
|
return false;
|
||||||
if (getClass() != obj.getClass())
|
}
|
||||||
|
if (getClass() != obj.getClass()) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
VariableLocFieldLocation other = (VariableLocFieldLocation) obj;
|
VariableLocFieldLocation other = (VariableLocFieldLocation) obj;
|
||||||
if (loc == null) {
|
if (loc == null) {
|
||||||
if (other.loc != null)
|
if (other.loc != null) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (!loc.equals(other.loc))
|
else if (!loc.equals(other.loc)) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,6 @@ import java.util.List;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.listing.CircularDependencyException;
|
import ghidra.program.model.listing.CircularDependencyException;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.program.util.ProgramLocation;
|
|
||||||
import ghidra.util.exception.DuplicateNameException;
|
import ghidra.util.exception.DuplicateNameException;
|
||||||
import ghidra.util.exception.InvalidInputException;
|
import ghidra.util.exception.InvalidInputException;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
@ -98,7 +97,7 @@ public class StubSymbol implements Symbol {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isValidParent(Namespace parent) {
|
public boolean isValidParent(Namespace nsParent) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,11 +131,6 @@ public class StubSymbol implements Symbol {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public ProgramLocation getProgramLocation() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setName(String newName, SourceType source)
|
public void setName(String newName, SourceType source)
|
||||||
throws DuplicateNameException, InvalidInputException {
|
throws DuplicateNameException, InvalidInputException {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue