Merge remote-tracking branch 'origin/patch'

This commit is contained in:
Ryan Kurtz 2023-10-20 18:42:02 -04:00
commit 771c8b1849
7 changed files with 550 additions and 38 deletions

View file

@ -0,0 +1,174 @@
/* ###
* 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.
*/
//
// This fixup script is intended to be run against x86 programs created prior
// to Ghidra 10.0.3 to update old ST0..ST7 floating point register
// locations assigned to function parameters and local variables. The
// address assignment for these registers was changed with Ghidra 10.0.3
// x86 slaspec change (GP-1228).
//
// This script can be run multiple times without harm
//@category Functions
import java.util.Set;
import ghidra.app.script.GhidraScript;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSpace;
import ghidra.program.model.lang.Register;
import ghidra.program.model.listing.*;
import ghidra.program.model.pcode.Varnode;
import ghidra.program.model.symbol.*;
import ghidra.util.exception.InvalidInputException;
public class FixOldSTVariableStorageScript extends GhidraScript {
private static final int ST_SIZE = 10;
// See Ghidra/Processors/x86/data/languages/ia.sinc
private static final long OLD_ST_BASE_OFFSET = 0x1000;
private static final long OLD_ST_OFFSET_SPACING = ST_SIZE; // each offset 10-bytes from the previous
// Must query new ST0 address since it may change again
private static final long NEW_ST_OFFSET_SPACING = 16; // each offset 16-bytes from the previous
@Override
protected void run() throws Exception {
if (currentProgram == null || !"x86".equals(currentProgram.getLanguage().getProcessor().toString())) {
popup("Script supports x86 programs only");
return;
}
// Spot check new ST0 placement
Register st0 = currentProgram.getRegister("ST0");
Register st1 = currentProgram.getRegister("ST1");
if (st0 == null || st1 == null) {
popup("Unsupported x86 language");
return;
}
long st0Offset = st0.getAddress().getOffset();
long st1Offset = st1.getAddress().getOffset();
if (st0Offset == OLD_ST_BASE_OFFSET || (st1Offset - st0Offset) != NEW_ST_OFFSET_SPACING) {
popup("Unsupported x86 ST register placement");
return;
}
STRegisterFixup stRegisterFixup = new STRegisterFixup(st0Offset);
int count = 0;
SymbolTable symbolTable = currentProgram.getSymbolTable();
for (Symbol s : symbolTable.getDefinedSymbols()) {
SymbolType type = s.getSymbolType();
if (type == SymbolType.PARAMETER || type == SymbolType.LOCAL_VAR) {
if (stRegisterFixup.fixupVariableStorage((Variable) s.getObject())) {
++count;
}
}
else if (type == SymbolType.FUNCTION) {
Function function = (Function) s.getObject();
if (stRegisterFixup.fixupVariableStorage(function.getReturn())) {
++count;
}
}
}
if (count != 0) {
popup("Fixed " + count + " ST register uses");
}
else {
popup("No old ST register uses were found");
}
}
private class STRegisterFixup {
private Set<Varnode> oldSTVarnodes; // ST0..ST7
private long newStBaseOffset;
STRegisterFixup(long newStBaseOffset) {
this.newStBaseOffset = newStBaseOffset;
AddressSpace registerSpace = currentProgram.getAddressFactory().getRegisterSpace();
long oldSTBaseOffset = OLD_ST_BASE_OFFSET;
oldSTVarnodes = Set.of(
new Varnode(registerSpace.getAddress(oldSTBaseOffset),
ST_SIZE), // Old ST0 at 0x1000, now at 0x1106
new Varnode(registerSpace.getAddress(oldSTBaseOffset + OLD_ST_OFFSET_SPACING),
ST_SIZE), // Old ST1 at 0x100a, now at 0x1116
new Varnode(registerSpace.getAddress(oldSTBaseOffset + (2 * OLD_ST_OFFSET_SPACING)),
ST_SIZE), // Old ST2 at 0x1014, now at 0x1126
new Varnode(registerSpace.getAddress(oldSTBaseOffset + (3 * OLD_ST_OFFSET_SPACING)),
ST_SIZE), // Old ST3 at 0x101e, now at 0x1136
new Varnode(registerSpace.getAddress(oldSTBaseOffset + (4 * OLD_ST_OFFSET_SPACING)),
ST_SIZE), // Old ST4 at 0x1028, now at 0x1146
new Varnode(registerSpace.getAddress(oldSTBaseOffset + (5 * OLD_ST_OFFSET_SPACING)),
ST_SIZE), // Old ST5 at 0x1032, now at 0x1156
new Varnode(registerSpace.getAddress(oldSTBaseOffset + (6 * OLD_ST_OFFSET_SPACING)),
ST_SIZE), // Old ST6 at 0x103c, now at 0x1166
new Varnode(registerSpace.getAddress(oldSTBaseOffset + (7 * OLD_ST_OFFSET_SPACING)),
ST_SIZE) // Old ST7 at 0x1046*, now at 0x1176 // Old ST7 at 0x1046, now at 0x1176
);
}
private boolean fixupVariableStorage(Variable var) {
VariableStorage varStore = var.getVariableStorage();
Varnode[] varnodes = varStore.getVarnodes();
if (fixupStorageVarnodes(varnodes)) {
try {
var.setDataType(var.getDataType(),
new VariableStorage(currentProgram, varnodes), false, var.getSource());
}
catch (InvalidInputException e) {
throw new AssertionError("Unexpected error for ST register varnode assignment",
e);
}
return true;
}
return false;
}
private boolean fixupStorageVarnodes(Varnode[] varnodes) {
boolean hasFixup = false;
for (int i = 0; i < varnodes.length; i++) {
Varnode v = getReplacement(varnodes[i]);
if (v != null) {
hasFixup = true;
varnodes[i] = v;
}
}
return hasFixup;
}
Varnode getReplacement(Varnode v) {
if (!oldSTVarnodes.contains(v)) {
return null;
}
Address regAddr = v.getAddress();
long stOffset = regAddr.getOffset() - OLD_ST_BASE_OFFSET;
long stIndex = stOffset / OLD_ST_OFFSET_SPACING;
// Form updated ST varnode
stOffset = newStBaseOffset + (stIndex * NEW_ST_OFFSET_SPACING);
return new Varnode(regAddr.getNewAddress(stOffset), 10);
}
}
}

View file

@ -17,6 +17,7 @@ package ghidra.framework.model;
import java.io.File;
import java.net.URL;
import java.util.Set;
import org.apache.commons.lang3.StringUtils;
@ -37,16 +38,30 @@ public class ProjectLocator {
private URL url;
/**
* Set of characters specifically disallowed in project name or path.
* These characters may interfere with path and URL parsing.
*/
public static Set<Character> DISALLOWED_CHARS = Set.of(':', ';', '&', '?', '#');
/**
* Construct a project locator object.
* @param path path to parent directory (may or may not exist). The user's temp directory
* will be used if this value is null or blank.
* @param path absolute path to parent directory (may or may not exist). The user's temp directory
* will be used if this value is null or blank. The use of "\" characters will always be replaced
* with "/".
* WARNING: Use of a relative paths should be avoided (e.g., on a windows platform
* an absolute path should start with a drive letter specification such as C:\path,
* while this same path on a Linux platform would be treated as relative).
* @param name name of the project
* an absolute path should start with a drive letter specification such as C:\path).
* A path such as "/path" on windows will utilize the current default drive and will
* not throw an exception. If a drive letter is specified it must specify an absolute
* path (e.g., C:\, C:\path).
* @param name name of the project (may only contain alphanumeric characters or
* @throws IllegalArgumentException if an absolute path is not specified or invalid project name
*/
public ProjectLocator(String path, String name) {
if (name.contains("/") || name.contains("\\")) {
throw new IllegalArgumentException("name contains path separator character: " + name);
}
checkInvalidChar("name", name, 0);
if (name.endsWith(PROJECT_FILE_SUFFIX)) {
name = name.substring(0, name.length() - PROJECT_FILE_SUFFIX.length());
}
@ -59,25 +74,75 @@ public class ProjectLocator {
}
/**
* Ensure that absolute path is specified.
* Check for characters explicitly disallowed in path or project name.
* @param type type of string to include in exception
* @param str string to check
* @param startIndex index at which to start checking
* @throws IllegalArgumentException if str contains invalid character
*/
private static void checkInvalidChar(String type, String str, int startIndex) {
for (int i = startIndex; i < str.length(); i++) {
char c = str.charAt(i);
if (DISALLOWED_CHARS.contains(c)) {
throw new IllegalArgumentException(
type + " contains invalid character: '" + c + "'");
}
}
}
/**
* Ensure that absolute path is specified and normalize its format.
* An absolute path may start with a windows drive letter (e.g., c:/a/b, /c:/a/b)
* or without (e.g., /a/b). Although for Windows the lack of a drive letter is
* not absolute, for consistency with Linux we permit this form which on
* Windows will use the default drive for the process. The resulting path
* may be transormed to always end with a "/" and if started with a drive letter
* (e.g., "c:/") it will have a "/" prepended (e.g., "/c:/", both forms
* are treated the same by the {@link File} class under Windows).
* @param path path to be checked and possibly modified.
* @return path to be used
* @throws IllegalArgumentException if an invalid path is specified
*/
private static String checkAbsolutePath(String path) {
if (path.startsWith("/") && path.length() >= 4 && path.indexOf(":/") == 2 &&
Character.isLetter(path.charAt(1))) {
// strip leading "/" on Windows paths (e.g., /C:/mydir) and transform separators to '\'
path = path.substring(1);
path = path.replace('/', '\\');
int scanIndex = 0;
path = path.replace('\\', '/');
int len = path.length();
if (!path.startsWith("/")) {
// Allow paths to start with windows drive letter (e.g., c:/a/b)
if (len >= 3 && hasAbsoluteDriveLetter(path, 0)) {
path = "/" + path;
}
else {
throw new IllegalArgumentException("absolute path required");
}
scanIndex = 3;
}
if (path.endsWith("/") || path.endsWith("\\")) {
path = path.substring(0, path.length() - 1);
else if (len >= 3 && hasDriveLetter(path, 1)) {
if (len < 4 || path.charAt(3) != '/') {
// path such as "/c:" not permitted
throw new IllegalArgumentException("absolute path required");
}
scanIndex = 4;
}
checkInvalidChar("path", path, scanIndex);
if (!path.endsWith(File.separator)) {
path += File.separator;
}
return path;
}
private static boolean hasDriveLetter(String path, int index) {
return Character.isLetter(path.charAt(index++)) && path.charAt(index) == ':';
}
private static boolean hasAbsoluteDriveLetter(String path, int index) {
int pathIndex = index + 2;
return path.length() > pathIndex && hasDriveLetter(path, index) &&
path.charAt(pathIndex) == '/';
}
/**
* Returns true if this project URL corresponds to a transient project
* @returns true if this project URL corresponds to a transient project
* (e.g., corresponds to remote Ghidra URL)
*/
public boolean isTransient() {
@ -85,7 +150,7 @@ public class ProjectLocator {
}
/**
* Returns the URL associated with this local project. If using a temporary transient
* @returns the URL associated with this local project. If using a temporary transient
* project location this URL should not be used.
*/
public URL getURL() {
@ -93,7 +158,7 @@ public class ProjectLocator {
}
/**
* Get the name of the project identified by this project info.
* @returns the name of the project identified by this project info.
*/
public String getName() {
return name;
@ -110,21 +175,21 @@ public class ProjectLocator {
}
/**
* Returns the project directory
* @returns the project directory
*/
public File getProjectDir() {
return new File(location, name + PROJECT_DIR_SUFFIX);
}
/**
* Returns the file that indicates a Ghidra project.
* @returns the file that indicates a Ghidra project.
*/
public File getMarkerFile() {
return new File(location, name + PROJECT_FILE_SUFFIX);
}
/**
* Returns project lock file to prevent multiple accesses to the
* @returns project lock file to prevent multiple accesses to the
* same project at once.
*/
public File getProjectLockFile() {
@ -132,7 +197,7 @@ public class ProjectLocator {
}
/**
* Returns the project directory file extension.
* @returns the project directory file extension.
*/
public static String getProjectDirExtension() {
return PROJECT_DIR_SUFFIX;
@ -164,7 +229,7 @@ public class ProjectLocator {
}
/**
* Returns the file extension suitable for creating file filters for the file chooser.
* @returns the file extension suitable for creating file filters for the file chooser.
*/
public static String getProjectExtension() {
return PROJECT_FILE_SUFFIX;
@ -180,7 +245,7 @@ public class ProjectLocator {
}
/**
* Returns true if project storage exists
* @returns true if project storage exists
*/
public boolean exists() {
return getMarkerFile().isFile() && getProjectDir().isDirectory();

View file

@ -15,6 +15,7 @@
*/
package ghidra.framework.protocol.ghidra;
import java.io.File;
import java.net.*;
import java.util.Objects;
import java.util.regex.Pattern;
@ -33,6 +34,8 @@ import ghidra.framework.remote.GhidraServerHandle;
*/
public class GhidraURL {
// TODO: URL encoding/decoding should be used
public static final String PROTOCOL = "ghidra";
private static final String PROTOCOL_URL_START = PROTOCOL + ":/";
@ -216,24 +219,67 @@ public class GhidraURL {
}
/**
* Ensure that absolute path is specified. Any use of Windows
* separator (back-slash) will be converted to a forward-slash.
* Ensure that absolute path is specified and normalize its format.
* An absolute path may start with a windows drive letter (e.g., c:/a/b, /c:/a/b)
* or without (e.g., /a/b). Although for Windows the lack of a drive letter is
* not absolute, for consistency with Linux we permit this form which on
* Windows will use the default drive for the process. If path starts with a drive
* letter (e.g., "c:/") it will have a "/" prepended (e.g., "/c:/", both forms
* are treated the same by the {@link File} class under Windows).
* @param path path to be checked and possibly modified.
* @return path to be used
* @throws IllegalArgumentException if an invalid path is specified
*/
private static String checkAbsolutePath(String path) {
int scanIndex = 0;
path = path.replace('\\', '/');
int len = path.length();
if (!path.startsWith("/")) {
if (path.length() >= 3 && path.indexOf(":/") == 1 &&
Character.isLetter(path.charAt(0))) {
// prepend a "/" on Windows paths (e.g., C:/mydir)
// Allow paths to start with windows drive letter (e.g., c:/a/b)
if (len >= 3 && hasAbsoluteDriveLetter(path, 0)) {
path = "/" + path;
}
else { // absence of drive letter is tolerated even if not absolute on windows
throw new IllegalArgumentException("Absolute directory path required");
else {
throw new IllegalArgumentException("absolute path required");
}
scanIndex = 3;
}
else if (len >= 3 && hasDriveLetter(path, 1)) {
if (len < 4 || path.charAt(3) != '/') {
// path such as "/c:" not permitted
throw new IllegalArgumentException("absolute path required");
}
scanIndex = 4;
}
checkInvalidChar("path", path, scanIndex);
return path;
}
private static boolean hasDriveLetter(String path, int index) {
return Character.isLetter(path.charAt(index++)) && path.charAt(index) == ':';
}
private static boolean hasAbsoluteDriveLetter(String path, int index) {
int pathIndex = index + 2;
return path.length() > pathIndex && hasDriveLetter(path, index) &&
path.charAt(pathIndex) == '/';
}
/**
* Check for characters explicitly disallowed in path or project name.
* @param type type of string to include in exception
* @param str string to check
* @param startIndex index at which to start checking
* @throws IllegalArgumentException if str contains invalid character
*/
private static void checkInvalidChar(String type, String str, int startIndex) {
for (int i = startIndex; i < str.length(); i++) {
char c = str.charAt(i);
if (ProjectLocator.DISALLOWED_CHARS.contains(c)) {
throw new IllegalArgumentException(
type + " contains invalid character: '" + c + "'");
}
}
return path;
}
/**
@ -256,8 +302,15 @@ public class GhidraURL {
throw new IllegalArgumentException("Unsupported query/ref used with project path");
}
projectPathOrURL = checkAbsolutePath(projectPathOrURL);
String[] splitName = splitOffName(projectPathOrURL);
return makeURL(splitName[0], splitName[1]);
int minSplitIndex = projectPathOrURL.charAt(2) == ':' ? 3 : 0;
int splitIndex = projectPathOrURL.lastIndexOf('/');
if (splitIndex < minSplitIndex || projectPathOrURL.length() == (splitIndex + 1)) {
throw new IllegalArgumentException("Absolute project path is missing project name");
}
++splitIndex;
String location = projectPathOrURL.substring(0, splitIndex);
String projectName = projectPathOrURL.substring(splitIndex);
return makeURL(location, projectName);
}
try {
return new URL(projectPathOrURL);
@ -467,11 +520,12 @@ public class GhidraURL {
* @param projectFilePath file path (e.g., /a/b/c, may be null)
* @param ref location reference (may be null)
* @return local Ghidra project URL
* @throws IllegalArgumentException if an absolute projectLocation path is not specified
*/
public static URL makeURL(String projectLocation, String projectName, String projectFilePath,
String ref) {
if (StringUtils.isBlank(projectLocation) || StringUtils.isBlank(projectName)) {
throw new IllegalArgumentException("Inavlid project location and/or name");
throw new IllegalArgumentException("Invalid project location and/or name");
}
String path = checkAbsolutePath(projectLocation);
if (!path.endsWith("/")) {

View file

@ -0,0 +1,182 @@
/* ###
* 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.framework.model;
import static org.junit.Assert.*;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import org.junit.Before;
import org.junit.Test;
import generic.test.AbstractGenericTest;
import ghidra.framework.OperatingSystem;
import ghidra.framework.protocol.ghidra.Handler;
public class ProjectLocatorTest extends AbstractGenericTest {
@Before
public void setUp() {
Handler.registerHandler();
}
//
// Behavior of test differs when run on Windows vs Linux/Mac
//
@Test
public void testPaths() throws MalformedURLException {
ProjectLocator pl = new ProjectLocator("c:\\", "bob");
assertEquals(new URL("ghidra:/c:/bob"), pl.getURL());
assertEquals("/c:/", pl.getLocation());
assertEquals(new File("/c:/bob.rep"), pl.getProjectDir());
assertEquals(new File("/c:/bob.gpr"), pl.getMarkerFile());
assertEquals("bob", pl.getName());
if (OperatingSystem.CURRENT_OPERATING_SYSTEM == OperatingSystem.WINDOWS) {
assertEquals("c:/bob.rep", pl.getProjectDir().getAbsolutePath());
assertEquals("c:/bob.gpr", pl.getMarkerFile().getAbsolutePath());
}
pl = new ProjectLocator("/c:/", "bob");
assertEquals(new URL("ghidra:/c:/bob"), pl.getURL());
assertEquals("/c:/", pl.getLocation());
assertEquals(new File("/c:/bob.rep"), pl.getProjectDir());
assertEquals(new File("/c:/bob.gpr"), pl.getMarkerFile());
assertEquals("bob", pl.getName());
if (OperatingSystem.CURRENT_OPERATING_SYSTEM == OperatingSystem.WINDOWS) {
assertEquals("c:/bob.rep", pl.getProjectDir().getAbsolutePath());
assertEquals("c:/bob.gpr", pl.getMarkerFile().getAbsolutePath());
}
pl = new ProjectLocator("c:\\a", "bob");
assertEquals(new URL("ghidra:/c:/a/bob"), pl.getURL());
assertEquals("/c:/a/", pl.getLocation());
assertEquals(new File("/c:/a/bob.rep"), pl.getProjectDir());
assertEquals(new File("/c:/a/bob.gpr"), pl.getMarkerFile());
assertEquals("bob", pl.getName());
if (OperatingSystem.CURRENT_OPERATING_SYSTEM == OperatingSystem.WINDOWS) {
assertEquals("c:/a/bob.rep", pl.getProjectDir().getAbsolutePath());
assertEquals("c:/a/bob.gpr", pl.getMarkerFile().getAbsolutePath());
}
pl = new ProjectLocator("c:\\a\\", "bob");
assertEquals(new URL("ghidra:/c:/a/bob"), pl.getURL());
assertEquals("/c:/a/", pl.getLocation());
assertEquals(new File("/c:/a/bob.rep"), pl.getProjectDir());
assertEquals(new File("/c:/a/bob.gpr"), pl.getMarkerFile());
assertEquals("bob", pl.getName());
if (OperatingSystem.CURRENT_OPERATING_SYSTEM == OperatingSystem.WINDOWS) {
assertEquals("c:/a/bob.rep", pl.getProjectDir().getAbsolutePath());
assertEquals("c:/a/bob.gpr", pl.getMarkerFile().getAbsolutePath());
}
pl = new ProjectLocator("\\", "bob");
assertEquals(new URL("ghidra:/bob"), pl.getURL());
assertEquals("/", pl.getLocation());
assertEquals(new File("/bob.rep"), pl.getProjectDir());
assertEquals(new File("/bob.gpr"), pl.getMarkerFile());
assertEquals("bob", pl.getName());
if (OperatingSystem.CURRENT_OPERATING_SYSTEM == OperatingSystem.WINDOWS) {
// NOTE: Sensitive to default drive for process
assertEquals("c:/bob.rep", pl.getProjectDir().getAbsolutePath());
assertEquals("c:/bob.gpr", pl.getMarkerFile().getAbsolutePath());
}
pl = new ProjectLocator("\\a\\", "bob");
assertEquals(new URL("ghidra:/a/bob"), pl.getURL());
assertEquals("/a/", pl.getLocation());
assertEquals(new File("/a/bob.rep"), pl.getProjectDir());
assertEquals(new File("/a/bob.gpr"), pl.getMarkerFile());
assertEquals("bob", pl.getName());
if (OperatingSystem.CURRENT_OPERATING_SYSTEM == OperatingSystem.WINDOWS) {
// NOTE: Sensitive to default drive for process
assertEquals("c:/a/bob.rep", pl.getProjectDir().getAbsolutePath());
assertEquals("c:/a/bob.gpr", pl.getMarkerFile().getAbsolutePath());
}
}
@Test
public void testTempPath() throws MalformedURLException {
String tmpPath = System.getProperty("java.io.tmpdir").replace("\\", "/");
if (!tmpPath.startsWith("/")) {
tmpPath = "/" + tmpPath;
}
if (!tmpPath.endsWith("/")) {
tmpPath += "/";
}
ProjectLocator pl = new ProjectLocator("", "bob");
assertEquals(tmpPath, pl.getLocation());
assertEquals(new URL("ghidra:" + tmpPath + "bob"), pl.getURL());
assertEquals(new File(pl.getLocation() + "bob.rep"), pl.getProjectDir());
assertEquals(new File(pl.getLocation() + "bob.gpr"), pl.getMarkerFile());
assertEquals("bob", pl.getName());
pl = new ProjectLocator(null, "bob");
assertEquals(tmpPath, pl.getLocation());
assertEquals(new URL("ghidra:" + tmpPath + "bob"), pl.getURL());
assertEquals(new File(pl.getLocation() + "bob.rep"), pl.getProjectDir());
assertEquals(new File(pl.getLocation() + "bob.gpr"), pl.getMarkerFile());
assertEquals("bob", pl.getName());
}
@Test
public void testBadPaths() {
// relative paths
doTestBadPath("c:", "bob");
doTestBadPath("/c:", "bob");
doTestBadPath("a/b", "bob");
// bad paths chars
doTestBadPath("/a?/b", "bob");
doTestBadPath("/a#/b", "bob");
doTestBadPath("/a/:b", "bob");
doTestBadPath("/a;/b", "bob");
doTestBadPath("/a&/b", "bob");
// bad name chars
doTestBadPath("/a/b", "b?ob");
doTestBadPath("/a/b", "b#ob");
doTestBadPath("/a/b", "b:ob");
doTestBadPath("/a/b", "b;ob");
doTestBadPath("/a/b", "b?ob");
doTestBadPath("/a/b", "b&ob");
doTestBadPath("/a/b", "b/ob");
doTestBadPath("/a/b", "b\\ob");
}
private void doTestBadPath(String path, String name) {
try {
new ProjectLocator(path, name);
fail("expected absolute path error");
}
catch (IllegalArgumentException e) {
// expected
}
}
}

View file

@ -793,8 +793,21 @@ public class HighFunctionDBUtil {
boolean nameCollision = false;
Variable[] localVariables =
function.getLocalVariables(VariableFilter.UNIQUE_VARIABLE_FILTER);
// Clean out any facet symbols with bad data-types
for (int i = 0; i < localVariables.length; ++i) {
Variable var = localVariables[i];
if (var.getName().startsWith(UnionFacetSymbol.BASENAME)) {
if (!UnionFacetSymbol.isUnionType(var.getDataType())) {
function.removeVariable(var);
localVariables[i] = null;
}
}
}
Variable preexistingVar = null;
for (Variable var : localVariables) {
if (var == null) {
continue;
}
if (var.getFirstUseOffset() == firstUseOffset &&
var.getFirstStorageVarnode().getOffset() == hash) {
preexistingVar = var;
@ -807,10 +820,12 @@ public class HighFunctionDBUtil {
symbolName = symbolName + '_' + Integer.toHexString(DynamicHash.getComparable(hash));
}
if (preexistingVar != null) {
if (preexistingVar.getName().equals(symbolName)) {
return; // No change to make
if (!preexistingVar.getName().equals(symbolName)) {
preexistingVar.setName(symbolName, source); // Change the name
}
if (!preexistingVar.getDataType().equals(dt)) {
preexistingVar.setDataType(dt, source);
}
preexistingVar.setName(symbolName, source); // Change the name
return;
}
Program program = function.getProgram();

View file

@ -453,7 +453,7 @@ public class LocalSymbolMap {
id = getNextId();
}
HighSymbol sym;
if (DynamicHash.getMethodFromHash(hash) > 3) {
if (DynamicHash.getMethodFromHash(hash) > 3 && UnionFacetSymbol.isUnionType(dt)) {
int fieldNum = UnionFacetSymbol.extractFieldNumber(nm);
sym = new UnionFacetSymbol(id, nm, dt, fieldNum, func);
}

View file

@ -21,7 +21,7 @@ import static ghidra.program.model.pcode.ElementId.*;
import java.io.IOException;
import ghidra.program.model.address.Address;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.*;
/**
* A specialized HighSymbol that directs the decompiler to use a specific field of a union,
@ -80,4 +80,26 @@ public class UnionFacetSymbol extends HighSymbol {
}
return Integer.decode(nm.substring(pos + BASENAME.length(), endpos)) - 1;
}
/**
* Return true if the given data-type is either a union or a pointer to a union
* and is suitable for being the data-type of UnionFacetSymbol
* @param dt is the given data-type
* @return true if the data-type is a union or a pointer to a union
*/
public static boolean isUnionType(DataType dt) {
if (dt instanceof TypeDef) {
dt = ((TypeDef) dt).getBaseDataType();
}
if (dt instanceof Pointer) {
dt = ((Pointer) dt).getDataType();
if (dt == null) {
return false;
}
if (dt instanceof TypeDef) {
dt = ((TypeDef) dt).getBaseDataType();
}
}
return (dt instanceof Union);
}
}