mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 10:49:34 +02:00
GP-706 - Speed up namespace lookup and creation
This commit is contained in:
parent
79fce9b032
commit
ae69ba87d1
35 changed files with 862 additions and 633 deletions
|
@ -17,10 +17,9 @@
|
||||||
//@category Examples
|
//@category Examples
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.*;
|
import java.util.List;
|
||||||
|
|
||||||
import generic.jar.ApplicationModule;
|
import generic.jar.ApplicationModule;
|
||||||
import generic.jar.ResourceFile;
|
|
||||||
import ghidra.app.script.GhidraScript;
|
import ghidra.app.script.GhidraScript;
|
||||||
import ghidra.framework.Application;
|
import ghidra.framework.Application;
|
||||||
import ghidra.util.GhidraJarBuilder;
|
import ghidra.util.GhidraJarBuilder;
|
||||||
|
@ -32,8 +31,7 @@ public class BuildGhidraJarScript extends GhidraScript {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() throws Exception {
|
public void run() throws Exception {
|
||||||
GhidraJarBuilder builder =
|
GhidraJarBuilder builder = new GhidraJarBuilder(Application.getApplicationLayout());
|
||||||
new GhidraJarBuilder(toFiles(Application.getApplicationRootDirectories()));
|
|
||||||
|
|
||||||
builder.setMainClass("ghidra.JarRun"); // default is ghidra.JarRun, only here if you want
|
builder.setMainClass("ghidra.JarRun"); // default is ghidra.JarRun, only here if you want
|
||||||
// to change it to something else.
|
// to change it to something else.
|
||||||
|
@ -69,12 +67,4 @@ public class BuildGhidraJarScript extends GhidraScript {
|
||||||
// uncomment the following line to create a src zip for debugging.
|
// uncomment the following line to create a src zip for debugging.
|
||||||
// builder.buildSrcZip(new File(installDir, "GhidraSrc.zip"), monitor);
|
// builder.buildSrcZip(new File(installDir, "GhidraSrc.zip"), monitor);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<File> toFiles(Collection<ResourceFile> resourceFiles) {
|
|
||||||
List<File> fileList = new ArrayList<>();
|
|
||||||
for (ResourceFile resourceFile : resourceFiles) {
|
|
||||||
fileList.add(resourceFile.getFile(true));
|
|
||||||
}
|
|
||||||
return fileList;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,8 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
import javax.swing.event.ChangeEvent;
|
import javax.swing.event.ChangeEvent;
|
||||||
import javax.swing.event.ChangeListener;
|
import javax.swing.event.ChangeListener;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import docking.ActionContext;
|
import docking.ActionContext;
|
||||||
import docking.ComponentProvider;
|
import docking.ComponentProvider;
|
||||||
import docking.dnd.GenericDataFlavor;
|
import docking.dnd.GenericDataFlavor;
|
||||||
|
@ -303,12 +305,9 @@ public class CodeBrowserClipboardProvider extends ByteCopier
|
||||||
private Transferable copyAddress() {
|
private Transferable copyAddress() {
|
||||||
|
|
||||||
AddressSetView addressSet = getSelectedAddresses();
|
AddressSetView addressSet = getSelectedAddresses();
|
||||||
StringBuilder buffy = new StringBuilder();
|
|
||||||
AddressIterator it = addressSet.getAddresses(true);
|
AddressIterator it = addressSet.getAddresses(true);
|
||||||
while (it.hasNext()) {
|
String joined = StringUtils.join((Iterator<Address>) it, "\n");
|
||||||
buffy.append(it.next()).append('\n');
|
return createStringTransferable(joined);
|
||||||
}
|
|
||||||
return createStringTransferable(buffy.toString());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Transferable copyCode(TaskMonitor monitor) {
|
protected Transferable copyCode(TaskMonitor monitor) {
|
||||||
|
@ -377,8 +376,8 @@ public class CodeBrowserClipboardProvider extends ByteCopier
|
||||||
private boolean pasteLabelsComments(Transferable pasteData, boolean pasteLabels,
|
private boolean pasteLabelsComments(Transferable pasteData, boolean pasteLabels,
|
||||||
boolean pasteComments) {
|
boolean pasteComments) {
|
||||||
try {
|
try {
|
||||||
List<?> list = (List<?>) pasteData.getTransferData(
|
List<?> list =
|
||||||
CodeUnitInfoTransferable.localDataTypeFlavor);
|
(List<?>) pasteData.getTransferData(CodeUnitInfoTransferable.localDataTypeFlavor);
|
||||||
List<CodeUnitInfo> infos = CollectionUtils.asList(list, CodeUnitInfo.class);
|
List<CodeUnitInfo> infos = CollectionUtils.asList(list, CodeUnitInfo.class);
|
||||||
Command cmd = new CodeUnitInfoPasteCmd(currentLocation.getAddress(), infos, pasteLabels,
|
Command cmd = new CodeUnitInfoPasteCmd(currentLocation.getAddress(), infos, pasteLabels,
|
||||||
pasteComments);
|
pasteComments);
|
||||||
|
@ -451,8 +450,8 @@ public class CodeBrowserClipboardProvider extends ByteCopier
|
||||||
String oldName = symbol.getName();
|
String oldName = symbol.getName();
|
||||||
Namespace namespace = symbol.getParentNamespace();
|
Namespace namespace = symbol.getParentNamespace();
|
||||||
Address symbolAddress = symbol.getAddress();
|
Address symbolAddress = symbol.getAddress();
|
||||||
RenameLabelCmd cmd = new RenameLabelCmd(symbolAddress, oldName, labelName,
|
RenameLabelCmd cmd = new RenameLabelCmd(symbolAddress, oldName, labelName, namespace,
|
||||||
namespace, SourceType.USER_DEFINED);
|
SourceType.USER_DEFINED);
|
||||||
return tool.execute(cmd, currentProgram);
|
return tool.execute(cmd, currentProgram);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -441,6 +441,7 @@ public abstract class DemangledObject implements Demangled {
|
||||||
namespace = program.getGlobalNamespace();
|
namespace = program.getGlobalNamespace();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SymbolTable symbolTable = program.getSymbolTable();
|
||||||
for (String namespaceName : getNamespaceList(typeNamespace)) {
|
for (String namespaceName : getNamespaceList(typeNamespace)) {
|
||||||
|
|
||||||
// TODO - This is compensating for too long templates. We should probably genericize
|
// TODO - This is compensating for too long templates. We should probably genericize
|
||||||
|
@ -448,16 +449,9 @@ public abstract class DemangledObject implements Demangled {
|
||||||
// same name is the same class--would that reflect reality?
|
// same name is the same class--would that reflect reality?
|
||||||
namespaceName = ensureNameLength(namespaceName);
|
namespaceName = ensureNameLength(namespaceName);
|
||||||
|
|
||||||
SymbolTable symbolTable = program.getSymbolTable();
|
|
||||||
|
|
||||||
List<Symbol> symbols = symbolTable.getSymbols(namespaceName, namespace);
|
|
||||||
Symbol namespaceSymbol =
|
|
||||||
symbols.stream().filter(s -> (s.getSymbolType() == SymbolType.NAMESPACE ||
|
|
||||||
s.getSymbolType() == SymbolType.CLASS)).findFirst().orElse(null);
|
|
||||||
if (namespaceSymbol == null) {
|
|
||||||
try {
|
try {
|
||||||
namespace =
|
namespace =
|
||||||
symbolTable.createNameSpace(namespace, namespaceName, SourceType.IMPORTED);
|
symbolTable.getOrCreateNameSpace(namespace, namespaceName, SourceType.IMPORTED);
|
||||||
}
|
}
|
||||||
catch (DuplicateNameException e) {
|
catch (DuplicateNameException e) {
|
||||||
Msg.error(DemangledObject.class,
|
Msg.error(DemangledObject.class,
|
||||||
|
@ -471,22 +465,27 @@ public abstract class DemangledObject implements Demangled {
|
||||||
"Failed to create namespace: " + e.getMessage());
|
"Failed to create namespace: " + e.getMessage());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Symbol nsSymbol = namespace.getSymbol();
|
||||||
|
if (!isPermittedNamespaceType(nsSymbol.getSymbolType(), functionPermitted)) {
|
||||||
|
|
||||||
|
String allowedTypes = "SymbolType.CLASS, SymbolType.NAMESPACE";
|
||||||
|
if (functionPermitted) {
|
||||||
|
allowedTypes += ", SymbolType.FUNCTION";
|
||||||
}
|
}
|
||||||
else if (isPermittedNamespaceSymbol(namespaceSymbol, functionPermitted)) {
|
|
||||||
namespace = (Namespace) namespaceSymbol.getObject();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Msg.error(DemangledObject.class,
|
Msg.error(DemangledObject.class,
|
||||||
"Failed to create namespace due to name conflict: " +
|
"Bad namespace type - must be one of: " + allowedTypes +
|
||||||
NamespaceUtils.getNamespaceQualifiedName(namespace, namespaceName, false));
|
NamespaceUtils.getNamespaceQualifiedName(namespace, namespaceName, false));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return namespace;
|
return namespace;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isPermittedNamespaceSymbol(Symbol symbol, boolean functionPermitted) {
|
private static boolean isPermittedNamespaceType(SymbolType symbolType,
|
||||||
SymbolType symbolType = symbol.getSymbolType();
|
boolean functionPermitted) {
|
||||||
if (symbolType == SymbolType.CLASS || symbolType == SymbolType.NAMESPACE) {
|
if (symbolType == SymbolType.CLASS || symbolType == SymbolType.NAMESPACE) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,8 +34,7 @@ import ghidra.program.model.scalar.Scalar;
|
||||||
import ghidra.program.model.symbol.Reference;
|
import ghidra.program.model.symbol.Reference;
|
||||||
import ghidra.program.model.symbol.ReferenceIterator;
|
import ghidra.program.model.symbol.ReferenceIterator;
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
import ghidra.util.exception.DuplicateNameException;
|
import ghidra.util.exception.*;
|
||||||
import ghidra.util.exception.NotFoundException;
|
|
||||||
|
|
||||||
public class VarnodeContext implements ProcessorContext {
|
public class VarnodeContext implements ProcessorContext {
|
||||||
|
|
||||||
|
@ -88,7 +87,7 @@ public class VarnodeContext implements ProcessorContext {
|
||||||
this.program = program;
|
this.program = program;
|
||||||
|
|
||||||
// make a copy, because we could be making new spaces.
|
// make a copy, because we could be making new spaces.
|
||||||
this.addrFactory = new OffsetAddressFactory(program.getAddressFactory());
|
this.addrFactory = new OffsetAddressFactory(program);
|
||||||
|
|
||||||
BAD_ADDRESS = addrFactory.getAddress(getAddressSpace("BAD_ADDRESS_SPACE"), 0);
|
BAD_ADDRESS = addrFactory.getAddress(getAddressSpace("BAD_ADDRESS_SPACE"), 0);
|
||||||
|
|
||||||
|
@ -1435,8 +1434,24 @@ public class VarnodeContext implements ProcessorContext {
|
||||||
|
|
||||||
class OffsetAddressFactory extends DefaultAddressFactory {
|
class OffsetAddressFactory extends DefaultAddressFactory {
|
||||||
|
|
||||||
OffsetAddressFactory(AddressFactory baseFactory) {
|
OffsetAddressFactory(Program program) {
|
||||||
super(filterSpaces(baseFactory.getAllAddressSpaces()));
|
// We are only calling super with the address spaces from the language first, and then
|
||||||
|
// following up to explicitly add more spaces due to the treatment of memory address
|
||||||
|
// spaces by DefaultAddressFactory when constructed vs. when added later.
|
||||||
|
// If there is more than one memory address space (e.g., TYPE_RAM, TYPE_CODE, or
|
||||||
|
// TYPE_OTHER), then addresses are output with the space name prefix, which we do not want.
|
||||||
|
super(program.getLanguage().getAddressFactory().getAllAddressSpaces(),
|
||||||
|
program.getLanguage().getAddressFactory().getDefaultAddressSpace());
|
||||||
|
for (AddressSpace space : program.getAddressFactory().getAllAddressSpaces()) {
|
||||||
|
if (space.isLoadedMemorySpace() && getAddressSpace(space.getName()) == null) {
|
||||||
|
try {
|
||||||
|
addAddressSpace(space);
|
||||||
|
}
|
||||||
|
catch (DuplicateNameException e) {
|
||||||
|
throw new AssertException("Duplicate name should not occur.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getNextUniqueID() {
|
private int getNextUniqueID() {
|
||||||
|
@ -1466,17 +1481,4 @@ class OffsetAddressFactory extends DefaultAddressFactory {
|
||||||
return (type == AddressSpace.TYPE_SYMBOL);
|
return (type == AddressSpace.TYPE_SYMBOL);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static AddressSpace[] filterSpaces(AddressSpace[] allSpaces) {
|
|
||||||
List<AddressSpace> spaces = new ArrayList<>();
|
|
||||||
for (AddressSpace space : allSpaces) {
|
|
||||||
int type = space.getType();
|
|
||||||
if (type == AddressSpace.TYPE_VARIABLE || type == AddressSpace.TYPE_STACK ||
|
|
||||||
type == AddressSpace.TYPE_EXTERNAL || type == AddressSpace.TYPE_JOIN) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
spaces.add(space);
|
|
||||||
}
|
|
||||||
return spaces.toArray(new AddressSpace[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,28 +25,24 @@ import java.util.zip.*;
|
||||||
import generic.jar.*;
|
import generic.jar.*;
|
||||||
import ghidra.GhidraApplicationLayout;
|
import ghidra.GhidraApplicationLayout;
|
||||||
import ghidra.GhidraLaunchable;
|
import ghidra.GhidraLaunchable;
|
||||||
import ghidra.framework.Application;
|
import ghidra.framework.*;
|
||||||
import ghidra.framework.HeadlessGhidraApplicationConfiguration;
|
|
||||||
import ghidra.framework.plugintool.dialog.ExtensionUtils;
|
import ghidra.framework.plugintool.dialog.ExtensionUtils;
|
||||||
import ghidra.util.classfinder.ClassFinder;
|
import ghidra.util.classfinder.ClassFinder;
|
||||||
import ghidra.util.classfinder.ClassSearcher;
|
import ghidra.util.classfinder.ClassSearcher;
|
||||||
import ghidra.util.exception.AssertException;
|
import ghidra.util.exception.AssertException;
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.CancelledException;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
import ghidra.util.task.TaskMonitorAdapter;
|
|
||||||
import utilities.util.FileUtilities;
|
import utilities.util.FileUtilities;
|
||||||
|
import utility.application.ApplicationLayout;
|
||||||
import utility.module.ModuleUtilities;
|
import utility.module.ModuleUtilities;
|
||||||
|
|
||||||
public class GhidraJarBuilder implements GhidraLaunchable {
|
public class GhidraJarBuilder implements GhidraLaunchable {
|
||||||
|
|
||||||
private static final String ROOT = "_Root/";
|
private static final String ROOT = "_Root/";
|
||||||
private static final String ROOT_GHIDRA = "_Root/Ghidra/";
|
private static final String ROOT_GHIDRA = "_Root/Ghidra/";
|
||||||
private static final String LIBS_FILE_MODULE_KEY = "Module: ";
|
|
||||||
|
|
||||||
// this is set in the buildGhidraJar batch/script files
|
// this is set in the buildGhidraJar batch/script files
|
||||||
private static final String GHIDRA_DIR = "Ghidra.Install.Root.Dir";
|
|
||||||
private static final String INVOCATION_NAME_PROPERTY = "GhidraJarBuilder.Name";
|
private static final String INVOCATION_NAME_PROPERTY = "GhidraJarBuilder.Name";
|
||||||
private static HashMap<String, List<String>> libsMap = new HashMap<>();
|
|
||||||
private List<File> rootGhidraDirs = new ArrayList<>();
|
private List<File> rootGhidraDirs = new ArrayList<>();
|
||||||
private List<ApplicationModule> allModules;
|
private List<ApplicationModule> allModules;
|
||||||
private Set<ApplicationModule> includedModules = new HashSet<>();
|
private Set<ApplicationModule> includedModules = new HashSet<>();
|
||||||
|
@ -57,19 +53,18 @@ public class GhidraJarBuilder implements GhidraLaunchable {
|
||||||
private Pattern extensionPointSuffixPattern;
|
private Pattern extensionPointSuffixPattern;
|
||||||
private List<String> extensionPointClasses = new ArrayList<>();
|
private List<String> extensionPointClasses = new ArrayList<>();
|
||||||
private ClassLoader classLoader;
|
private ClassLoader classLoader;
|
||||||
private boolean inGradleMode = false;
|
|
||||||
private Set<File> processedJars = new HashSet<>();
|
private Set<File> processedJars = new HashSet<>();
|
||||||
|
|
||||||
public GhidraJarBuilder() {
|
public GhidraJarBuilder() {
|
||||||
// Required for GhidraLaunchable
|
// Required for GhidraLaunchable
|
||||||
}
|
}
|
||||||
|
|
||||||
public GhidraJarBuilder(List<File> rootDirs) throws IOException {
|
public GhidraJarBuilder(ApplicationLayout layout) throws IOException {
|
||||||
for (File file : rootDirs) {
|
for (ResourceFile file : layout.getApplicationRootDirs()) {
|
||||||
File rgd = file.getCanonicalFile();
|
File rgd = file.getFile(false).getCanonicalFile();
|
||||||
rootGhidraDirs.add(rgd);
|
rootGhidraDirs.add(rgd);
|
||||||
}
|
}
|
||||||
allModules = findAllModules();
|
allModules = findAllModules(layout);
|
||||||
Collections.sort(allModules);
|
Collections.sort(allModules);
|
||||||
for (ApplicationModule module : allModules) {
|
for (ApplicationModule module : allModules) {
|
||||||
if (includeByDefault(module)) {
|
if (includeByDefault(module)) {
|
||||||
|
@ -203,7 +198,7 @@ public class GhidraJarBuilder implements GhidraLaunchable {
|
||||||
|
|
||||||
for (ApplicationModule module : moduleList) {
|
for (ApplicationModule module : moduleList) {
|
||||||
writeModuleClassesAndResources(jar, module);
|
writeModuleClassesAndResources(jar, module);
|
||||||
if (!excludeHelp && !inGradleMode) {
|
if (!excludeHelp) {
|
||||||
writeModuleHelp(jar, module);
|
writeModuleHelp(jar, module);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -360,16 +355,6 @@ public class GhidraJarBuilder implements GhidraLaunchable {
|
||||||
private void writeModuleClassesAndResources(Jar jar, ApplicationModule module)
|
private void writeModuleClassesAndResources(Jar jar, ApplicationModule module)
|
||||||
throws CancelledException, IOException {
|
throws CancelledException, IOException {
|
||||||
|
|
||||||
if (inGradleMode) {
|
|
||||||
File gradleBuildFileForModule =
|
|
||||||
new File(module.getModuleDir(), "build/libs/" + module.getName() + ".jar");
|
|
||||||
processJarFile(jar, gradleBuildFileForModule, module);
|
|
||||||
File gradleBuildFileForGPLModule =
|
|
||||||
new File(module.getModuleDir(), "build/data/lib/" + module.getName() + ".jar");
|
|
||||||
processJarFile(jar, gradleBuildFileForGPLModule, module);
|
|
||||||
processExternalLibs(jar, module);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// NOTE: This only works in a distribution where the 3rd party jars live in each
|
// NOTE: This only works in a distribution where the 3rd party jars live in each
|
||||||
// module's libs directory
|
// module's libs directory
|
||||||
File binDir = new File(module.getModuleDir(), "bin/main");
|
File binDir = new File(module.getModuleDir(), "bin/main");
|
||||||
|
@ -380,18 +365,6 @@ public class GhidraJarBuilder implements GhidraLaunchable {
|
||||||
processLibDir(jar, module);
|
processLibDir(jar, module);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processExternalLibs(Jar jar, ApplicationModule module)
|
|
||||||
throws CancelledException, IOException {
|
|
||||||
List<String> list = libsMap.get(module.getName());
|
|
||||||
if (list == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (String libPath : list) {
|
|
||||||
File file = new File(libPath);
|
|
||||||
processJarFile(jar, file, module);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void processLibDir(Jar jar, ApplicationModule module)
|
private void processLibDir(Jar jar, ApplicationModule module)
|
||||||
throws CancelledException, IOException {
|
throws CancelledException, IOException {
|
||||||
File libDir = new File(module.getModuleDir(), "lib");
|
File libDir = new File(module.getModuleDir(), "lib");
|
||||||
|
@ -586,16 +559,34 @@ public class GhidraJarBuilder implements GhidraLaunchable {
|
||||||
return manifest;
|
return manifest;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<ApplicationModule> findAllModules() {
|
private List<ApplicationModule> findAllModules(ApplicationLayout layout) throws IOException {
|
||||||
List<ApplicationModule> modules = new ArrayList<>();
|
List<ApplicationModule> modules = new ArrayList<>();
|
||||||
for (File appRoot : rootGhidraDirs) {
|
|
||||||
findModules(appRoot, appRoot, modules);
|
|
||||||
findModules(appRoot, new File(appRoot, "../GPL"), modules);
|
|
||||||
|
|
||||||
|
for (GModule module : layout.getModules().values()) {
|
||||||
|
File moduleDir = module.getModuleRoot().getFile(false).getCanonicalFile();
|
||||||
|
File rootDir = getModuleRootDir(moduleDir);
|
||||||
|
modules.add(new ApplicationModule(rootDir, moduleDir));
|
||||||
}
|
}
|
||||||
|
|
||||||
return modules;
|
return modules;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private File getModuleRootDir(File moduleDir) {
|
||||||
|
// Look in GPL directories too
|
||||||
|
List<File> rootDirs = new ArrayList<>(rootGhidraDirs);
|
||||||
|
for (File rootDir : rootGhidraDirs) {
|
||||||
|
rootDirs.add(new File(rootDir.getParentFile(), "GPL"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check each root directory to see if it contains the module
|
||||||
|
for (File rootDir : rootDirs) {
|
||||||
|
if (FileUtilities.isPathContainedWithin(rootDir, moduleDir)) {
|
||||||
|
return rootDir;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new AssertException("Module root directory could not be determined: " + moduleDir);
|
||||||
|
}
|
||||||
|
|
||||||
private String getPathFromRoot(String rootPath, File file) {
|
private String getPathFromRoot(String rootPath, File file) {
|
||||||
String filePath = file.getAbsolutePath();
|
String filePath = file.getAbsolutePath();
|
||||||
if (!filePath.startsWith(rootPath)) {
|
if (!filePath.startsWith(rootPath)) {
|
||||||
|
@ -604,23 +595,6 @@ public class GhidraJarBuilder implements GhidraLaunchable {
|
||||||
return filePath.substring(rootPath.length() + 1);
|
return filePath.substring(rootPath.length() + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void findModules(File rootAppDir, File dir, List<ApplicationModule> modules) {
|
|
||||||
File moduleManifest = new File(dir, "Module.manifest");
|
|
||||||
if (moduleManifest.exists()) {
|
|
||||||
ApplicationModule module = new ApplicationModule(rootAppDir, dir);
|
|
||||||
modules.add(module);
|
|
||||||
return; // modules can't live in other modules;
|
|
||||||
}
|
|
||||||
File[] listFiles = dir.listFiles();
|
|
||||||
if (listFiles != null) {
|
|
||||||
for (File file : listFiles) {
|
|
||||||
if (file.isDirectory()) {
|
|
||||||
findModules(rootAppDir, file, modules);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void checkExtensionPointClass(String path, InputStream inputStream) {
|
private void checkExtensionPointClass(String path, InputStream inputStream) {
|
||||||
// remove .class
|
// remove .class
|
||||||
path = path.substring(0, path.length() - 6);
|
path = path.substring(0, path.length() - 6);
|
||||||
|
@ -931,44 +905,15 @@ public class GhidraJarBuilder implements GhidraLaunchable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void parseLibsFile(String libsFilePath) {
|
|
||||||
try {
|
|
||||||
List<String> lines = FileUtilities.getLines(new File(libsFilePath));
|
|
||||||
|
|
||||||
List<String> libPaths = new ArrayList<>();
|
|
||||||
String currentModule = null;
|
|
||||||
for (String line : lines) {
|
|
||||||
if (line.startsWith(LIBS_FILE_MODULE_KEY)) {
|
|
||||||
if (currentModule != null) {
|
|
||||||
libsMap.put(currentModule, libPaths);
|
|
||||||
libPaths = new ArrayList<>();
|
|
||||||
}
|
|
||||||
currentModule = line.substring(LIBS_FILE_MODULE_KEY.length()).trim();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
libPaths.add(line.trim());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (IOException e) {
|
|
||||||
System.err.println("Could not read lib paths file: " + libsFilePath);
|
|
||||||
System.exit(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void usage(String[] args) {
|
private static void usage(String[] args) {
|
||||||
for (int i = 0; i < args.length; i++) {
|
for (int i = 0; i < args.length; i++) {
|
||||||
System.err.println("arg " + i + ": " + args[i]);
|
System.err.println("arg " + i + ": " + args[i]);
|
||||||
}
|
}
|
||||||
String invocationName = System.getProperty(INVOCATION_NAME_PROPERTY);
|
String invocationName = System.getProperty(INVOCATION_NAME_PROPERTY);
|
||||||
String property = System.getProperty(GHIDRA_DIR);
|
|
||||||
|
|
||||||
StringBuffer buf = new StringBuffer();
|
StringBuffer buf = new StringBuffer();
|
||||||
buf.append("\nUsage: ");
|
buf.append("\nUsage: ");
|
||||||
buf.append(invocationName != null ? invocationName : "GhidraJarBuilder");
|
buf.append(invocationName != null ? invocationName : "GhidraJarBuilder");
|
||||||
if (property == null) {
|
|
||||||
buf.append("<Installation Root Directory> [<Installation Root Directory> ...] ");
|
|
||||||
}
|
|
||||||
buf.append(
|
buf.append(
|
||||||
" [-output <output file>] [-srczip <src zip output file>] [-bin <compiled classes dir>] [-main <main-class>]\n");
|
" [-output <output file>] [-srczip <src zip output file>] [-bin <compiled classes dir>] [-main <main-class>]\n");
|
||||||
System.err.println(buf.toString());
|
System.err.println(buf.toString());
|
||||||
|
@ -992,17 +937,10 @@ public class GhidraJarBuilder implements GhidraLaunchable {
|
||||||
usage(args);
|
usage(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<File> ghidraDirs = new ArrayList<>();
|
|
||||||
File outputFile = null;
|
File outputFile = null;
|
||||||
File srczip = null;
|
File srczip = null;
|
||||||
File extraBinDir = null;
|
File extraBinDir = null;
|
||||||
String mainClassArg = null;
|
String mainClassArg = null;
|
||||||
boolean usingGradle = false;
|
|
||||||
|
|
||||||
String property = System.getProperty(GHIDRA_DIR);
|
|
||||||
if (property != null) {
|
|
||||||
ghidraDirs.add(new File(property));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < args.length; i++) {
|
for (int i = 0; i < args.length; i++) {
|
||||||
String arg = args[i];
|
String arg = args[i];
|
||||||
|
@ -1030,28 +968,14 @@ public class GhidraJarBuilder implements GhidraLaunchable {
|
||||||
}
|
}
|
||||||
mainClassArg = args[++i];
|
mainClassArg = args[++i];
|
||||||
}
|
}
|
||||||
else if (arg.equals("-gradle")) {
|
|
||||||
if (i == args.length - 1) {
|
|
||||||
usage(args);
|
|
||||||
}
|
|
||||||
usingGradle = true;
|
|
||||||
parseLibsFile(args[++i]);
|
|
||||||
}
|
|
||||||
else if (arg.startsWith("-")) {
|
|
||||||
usage(args);
|
|
||||||
}
|
|
||||||
else {
|
else {
|
||||||
ghidraDirs.add(new File(arg));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (ghidraDirs.isEmpty()) {
|
|
||||||
usage(args);
|
usage(args);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (outputFile == null) {
|
if (outputFile == null) {
|
||||||
outputFile = new File("ghidra.jar");
|
outputFile = new File("ghidra.jar");
|
||||||
}
|
}
|
||||||
|
|
||||||
System.out.println("Ghidra dirs = " + ghidraDirs);
|
|
||||||
System.out.println("Output file = " + outputFile);
|
System.out.println("Output file = " + outputFile);
|
||||||
if (srczip != null) {
|
if (srczip != null) {
|
||||||
System.out.println("Source Zip File = " + srczip);
|
System.out.println("Source Zip File = " + srczip);
|
||||||
|
@ -1061,13 +985,10 @@ public class GhidraJarBuilder implements GhidraLaunchable {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
GhidraJarBuilder builder = new GhidraJarBuilder(ghidraDirs);
|
GhidraJarBuilder builder = new GhidraJarBuilder(layout);
|
||||||
if (mainClassArg != null) {
|
if (mainClassArg != null) {
|
||||||
builder.setMainClass(mainClassArg);
|
builder.setMainClass(mainClassArg);
|
||||||
}
|
}
|
||||||
if (usingGradle) {
|
|
||||||
builder.setGradleMode();
|
|
||||||
}
|
|
||||||
builder.addExcludedFileExtension(".pdf");
|
builder.addExcludedFileExtension(".pdf");
|
||||||
|
|
||||||
// builder.addExcludedFileExtension(".htm");
|
// builder.addExcludedFileExtension(".htm");
|
||||||
|
@ -1082,10 +1003,10 @@ public class GhidraJarBuilder implements GhidraLaunchable {
|
||||||
System.out.println("Exclude " + module.getName());
|
System.out.println("Exclude " + module.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.buildJar(outputFile, extraBinDir, TaskMonitorAdapter.DUMMY_MONITOR);
|
builder.buildJar(outputFile, extraBinDir, TaskMonitor.DUMMY);
|
||||||
|
|
||||||
if (srczip != null) {
|
if (srczip != null) {
|
||||||
builder.buildSrcZip(srczip, TaskMonitorAdapter.DUMMY_MONITOR);
|
builder.buildSrcZip(srczip, TaskMonitor.DUMMY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
|
@ -1099,8 +1020,4 @@ public class GhidraJarBuilder implements GhidraLaunchable {
|
||||||
return new File(ghidraRootDir, "application.properties");
|
return new File(ghidraRootDir, "application.properties");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setGradleMode() {
|
|
||||||
inGradleMode = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
/* ###
|
/* ###
|
||||||
* IP: Apache License 2.0
|
* IP: Apache License 2.0
|
||||||
*
|
*/
|
||||||
|
/***
|
||||||
* This is fix for a bug found in the Felix Framework:
|
* This is fix for a bug found in the Felix Framework:
|
||||||
*
|
*
|
||||||
* https://issues.apache.org/jira/browse/FELIX-6297
|
* https://issues.apache.org/jira/browse/FELIX-6297
|
||||||
|
@ -9,8 +10,8 @@
|
||||||
*
|
*
|
||||||
* THIS FILE SHOULD BE REMOVED WHEN THE ISSUE IS ADDRESSED.
|
* THIS FILE SHOULD BE REMOVED WHEN THE ISSUE IS ADDRESSED.
|
||||||
*
|
*
|
||||||
*/
|
***
|
||||||
/*
|
*
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
* or more contributor license agreements. See the NOTICE file
|
* or more contributor license agreements. See the NOTICE file
|
||||||
* distributed with this work for additional information
|
* distributed with this work for additional information
|
||||||
|
@ -30,24 +31,15 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.felix.framework.util;
|
package org.apache.felix.framework.util;
|
||||||
|
|
||||||
import org.apache.felix.framework.cache.Content;
|
|
||||||
import org.osgi.framework.Version;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Enumeration;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.LinkedHashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.jar.Attributes;
|
|
||||||
import java.util.jar.Manifest;
|
import java.util.jar.Manifest;
|
||||||
|
|
||||||
|
import org.apache.felix.framework.cache.Content;
|
||||||
|
import org.osgi.framework.Version;
|
||||||
|
|
||||||
public class MultiReleaseContent implements Content
|
public class MultiReleaseContent implements Content
|
||||||
{
|
{
|
||||||
private final Content m_content;
|
private final Content m_content;
|
||||||
|
|
|
@ -840,6 +840,22 @@
|
||||||
location when zooming from the middle-mouse. The default for this option is off, which
|
location when zooming from the middle-mouse. The default for this option is off, which
|
||||||
triggers zoom to work from the center of the graph, regardless of the mouse location.</P>
|
triggers zoom to work from the center of the graph, regardless of the mouse location.</P>
|
||||||
|
|
||||||
|
<P>The <B>View Settings</B> option describes how the graph will be zoomed when it is first
|
||||||
|
loaded. The values are:</P>
|
||||||
|
|
||||||
|
<UL>
|
||||||
|
<LI><B>Start Fully Zoomed Out</B> - always start fully zoomed out so that the entire
|
||||||
|
graph can be seen.</LI>
|
||||||
|
|
||||||
|
<LI><B>Start Fully Zoomed In/B> - always start fully zoomed in on the vertex containing
|
||||||
|
the current location.</LI>
|
||||||
|
|
||||||
|
<LI><B>Remember User Settings</B> - keep the zoom level where the user previously left
|
||||||
|
it.</LI>
|
||||||
|
</UL>
|
||||||
|
<BR>
|
||||||
|
<BR>
|
||||||
|
|
||||||
<P>There are various edge color and highlight color options available to change. The
|
<P>There are various edge color and highlight color options available to change. The
|
||||||
highlight colors are those to be used when the flow animations take place.</P>
|
highlight colors are those to be used when the flow animations take place.</P>
|
||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
|
|
|
@ -50,6 +50,13 @@
|
||||||
</P>
|
</P>
|
||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
|
<BLOCKQUOTE>
|
||||||
|
<P>The <B>Use Dim Return Edges</B> option makes default code block return flow edges
|
||||||
|
lighter than conditional edges. This makes it easier for users to scan the
|
||||||
|
graph and ignore return flows.
|
||||||
|
</P>
|
||||||
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -185,8 +185,8 @@ public class FunctionGraphOptions extends VisualGraphOptions {
|
||||||
options.registerOption(SCROLL_WHEEL_PANS_KEY, getScrollWheelPans(), help,
|
options.registerOption(SCROLL_WHEEL_PANS_KEY, getScrollWheelPans(), help,
|
||||||
SCROLL_WHEEL_PANS_DESCRIPTION);
|
SCROLL_WHEEL_PANS_DESCRIPTION);
|
||||||
|
|
||||||
options.registerOption(GRAPH_BACKGROUND_COLOR_KEY, DEFAULT_GRAPH_BACKGROUND_COLOR,
|
options.registerOption(GRAPH_BACKGROUND_COLOR_KEY, DEFAULT_GRAPH_BACKGROUND_COLOR, help,
|
||||||
help, GRAPH_BACKGROUND_COLOR_DESCRPTION);
|
GRAPH_BACKGROUND_COLOR_DESCRPTION);
|
||||||
|
|
||||||
options.registerOption(DEFAULT_VERTEX_BACKGROUND_COLOR_KEY, DEFAULT_VERTEX_BACKGROUND_COLOR,
|
options.registerOption(DEFAULT_VERTEX_BACKGROUND_COLOR_KEY, DEFAULT_VERTEX_BACKGROUND_COLOR,
|
||||||
help, DEFAULT_VERTEX_BACKGROUND_COLOR_DESCRPTION);
|
help, DEFAULT_VERTEX_BACKGROUND_COLOR_DESCRPTION);
|
||||||
|
|
|
@ -31,7 +31,12 @@ public class DNLayoutOptions implements FGLayoutOptions {
|
||||||
"edges should be routed around any intersecting vertex. When toggled off, edges will " +
|
"edges should be routed around any intersecting vertex. When toggled off, edges will " +
|
||||||
"pass through any intersecting vertices.";
|
"pass through any intersecting vertices.";
|
||||||
|
|
||||||
|
private static final String DIM_RETURN_EDGES_KEY = "Use Dim Return Edges";
|
||||||
|
private static final String DIM_RETURN_EDGES_DESCRIPTION =
|
||||||
|
"Signals to lighten the default return edges.";
|
||||||
|
|
||||||
private boolean useEdgeRoutingAroundVertices;
|
private boolean useEdgeRoutingAroundVertices;
|
||||||
|
private boolean useDimmedReturnEdges = true;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void registerOptions(Options options) {
|
public void registerOptions(Options options) {
|
||||||
|
@ -40,21 +45,32 @@ public class DNLayoutOptions implements FGLayoutOptions {
|
||||||
|
|
||||||
options.registerOption(USE_EDGE_ROUTING_AROUND_VERTICES_KEY, useEdgeRoutingAroundVertices,
|
options.registerOption(USE_EDGE_ROUTING_AROUND_VERTICES_KEY, useEdgeRoutingAroundVertices,
|
||||||
help, USE_EDGE_ROUTING_AROUND_VERTICES_DESCRIPTION);
|
help, USE_EDGE_ROUTING_AROUND_VERTICES_DESCRIPTION);
|
||||||
|
|
||||||
|
options.registerOption(DIM_RETURN_EDGES_KEY, useDimmedReturnEdges, help,
|
||||||
|
DIM_RETURN_EDGES_DESCRIPTION);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void loadOptions(Options options) {
|
public void loadOptions(Options options) {
|
||||||
useEdgeRoutingAroundVertices =
|
useEdgeRoutingAroundVertices =
|
||||||
options.getBoolean(USE_EDGE_ROUTING_AROUND_VERTICES_KEY, useEdgeRoutingAroundVertices);
|
options.getBoolean(USE_EDGE_ROUTING_AROUND_VERTICES_KEY, useEdgeRoutingAroundVertices);
|
||||||
|
|
||||||
|
useDimmedReturnEdges = options.getBoolean(DIM_RETURN_EDGES_KEY, useDimmedReturnEdges);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean useEdgeRoutingAroundVertices() {
|
public boolean useEdgeRoutingAroundVertices() {
|
||||||
return useEdgeRoutingAroundVertices;
|
return useEdgeRoutingAroundVertices;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean useDimmedReturnEdges() {
|
||||||
|
return useDimmedReturnEdges;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean optionChangeRequiresRelayout(String optionName) {
|
public boolean optionChangeRequiresRelayout(String optionName) {
|
||||||
// format: 'Nested Code Layout.Route Edges....'
|
// format: 'Nested Code Layout.Route Edges....'
|
||||||
return optionName.endsWith(USE_EDGE_ROUTING_AROUND_VERTICES_KEY);
|
return optionName.endsWith(USE_EDGE_ROUTING_AROUND_VERTICES_KEY) ||
|
||||||
|
optionName.endsWith(DIM_RETURN_EDGES_KEY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,6 +38,7 @@ import ghidra.app.plugin.core.functiongraph.graph.jung.renderer.DNLArticulatedEd
|
||||||
import ghidra.app.plugin.core.functiongraph.graph.vertex.FGVertex;
|
import ghidra.app.plugin.core.functiongraph.graph.vertex.FGVertex;
|
||||||
import ghidra.app.plugin.core.functiongraph.graph.vertex.GroupedFunctionGraphVertex;
|
import ghidra.app.plugin.core.functiongraph.graph.vertex.GroupedFunctionGraphVertex;
|
||||||
import ghidra.graph.VisualGraph;
|
import ghidra.graph.VisualGraph;
|
||||||
|
import ghidra.graph.viewer.GraphViewerUtils;
|
||||||
import ghidra.graph.viewer.layout.*;
|
import ghidra.graph.viewer.layout.*;
|
||||||
import ghidra.graph.viewer.vertex.VisualGraphVertexShapeTransformer;
|
import ghidra.graph.viewer.vertex.VisualGraphVertexShapeTransformer;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
|
@ -262,11 +263,8 @@ public class DecompilerNestedLayout extends AbstractFGLayout {
|
||||||
DecompilerBlock loop = block.getParentLoop();
|
DecompilerBlock loop = block.getParentLoop();
|
||||||
|
|
||||||
if (loop != null) {
|
if (loop != null) {
|
||||||
Set<FGVertex> vertices = loop.getVertices();
|
List<Point2D> articulations =
|
||||||
|
routeUpwardLoop(layoutToGridMap, vertex2dFactory, start, end, loop);
|
||||||
Column outermostCol = getOutermostCol(layoutToGridMap, vertices);
|
|
||||||
Column loopEndColumn = layoutToGridMap.nextColumn(outermostCol);
|
|
||||||
List<Point2D> articulations = routeLoopEdge(start, end, loopEndColumn);
|
|
||||||
newEdgeArticulations.put(e, articulations);
|
newEdgeArticulations.put(e, articulations);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -331,6 +329,70 @@ public class DecompilerNestedLayout extends AbstractFGLayout {
|
||||||
return newEdgeArticulations;
|
return newEdgeArticulations;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<Point2D> routeUpwardLoop(LayoutLocationMap<FGVertex, FGEdge> layoutToGridMap,
|
||||||
|
Vertex2dFactory vertex2dFactory, Vertex2d start, Vertex2d end, DecompilerBlock loop) {
|
||||||
|
Set<FGVertex> loopVertices = loop.getVertices();
|
||||||
|
FGVertex rightmostLoopVertex =
|
||||||
|
getRightmostVertex(layoutToGridMap, vertex2dFactory, loopVertices);
|
||||||
|
|
||||||
|
int startRow = start.rowIndex;
|
||||||
|
int endRow = end.rowIndex;
|
||||||
|
int startColumn = Math.min(start.columnIndex, end.columnIndex);
|
||||||
|
int endColumn = Math.max(start.columnIndex, end.columnIndex);
|
||||||
|
|
||||||
|
Column rightmostLoopColumn = layoutToGridMap.col(rightmostLoopVertex);
|
||||||
|
endColumn = Math.max(endColumn, rightmostLoopColumn.index);
|
||||||
|
|
||||||
|
// Look for any vertices that are no part of the loop, but are placed inside
|
||||||
|
// of the loop bounds. This can happen in a graph when the decompiler uses
|
||||||
|
// goto statements. Use the loop's rightmost vertex to establish the loops
|
||||||
|
// right edge and then use that to check for any stray non-loop vertices.
|
||||||
|
List<Vertex2d> interlopers =
|
||||||
|
getVerticesInBounds(vertex2dFactory, startRow, endRow, startColumn, endColumn);
|
||||||
|
|
||||||
|
// place the right x position to the right of the rightmost vertex, not
|
||||||
|
// extending past the next column
|
||||||
|
FGVertex rightmostVertex = getRightmostVertex(interlopers);
|
||||||
|
Column rightmostColumn = layoutToGridMap.col(rightmostVertex);
|
||||||
|
Column nextColumn = layoutToGridMap.nextColumn(rightmostColumn);
|
||||||
|
Vertex2d rightmostV2d = vertex2dFactory.get(rightmostVertex);
|
||||||
|
|
||||||
|
// the padding used for these two lines is somewhat arbitrary and may be changed
|
||||||
|
double rightSide = rightmostV2d.getRight() + GraphViewerUtils.EXTRA_LAYOUT_COLUMN_SPACING;
|
||||||
|
double x = Math.min(rightSide,
|
||||||
|
nextColumn.x - GraphViewerUtils.EXTRA_LAYOUT_COLUMN_SPACING_CONDENSED);
|
||||||
|
|
||||||
|
List<Point2D> articulations = routeLoopEdge(start, end, x);
|
||||||
|
return articulations;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Vertex2d> getVerticesInBounds(Vertex2dFactory vertex2dFactory, int startRow,
|
||||||
|
int endRow, int startColumn, int endColumn) {
|
||||||
|
|
||||||
|
if (startRow > endRow) { // going upwards
|
||||||
|
int temp = endRow;
|
||||||
|
endRow = startRow;
|
||||||
|
startRow = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Vertex2d> toCheck = new LinkedList<>();
|
||||||
|
for (int row = startRow; row < endRow + 1; row++) {
|
||||||
|
|
||||||
|
for (int col = startColumn; col < endColumn + 1; col++) {
|
||||||
|
|
||||||
|
// assume any other vertex in our column can clip (it will not clip when
|
||||||
|
// the 'spacing' above pushes the edge away from this column, like for
|
||||||
|
// large row delta values)
|
||||||
|
Vertex2d otherVertex = vertex2dFactory.get(row, col);
|
||||||
|
if (otherVertex != null) {
|
||||||
|
toCheck.add(otherVertex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return toCheck;
|
||||||
|
}
|
||||||
|
|
||||||
private void routeToTheRightGoingUpwards(Vertex2d start, Vertex2d end,
|
private void routeToTheRightGoingUpwards(Vertex2d start, Vertex2d end,
|
||||||
Vertex2dFactory vertex2dFactory, List<Point2D> articulations) {
|
Vertex2dFactory vertex2dFactory, List<Point2D> articulations) {
|
||||||
|
|
||||||
|
@ -347,11 +409,16 @@ public class DecompilerNestedLayout extends AbstractFGLayout {
|
||||||
}
|
}
|
||||||
int distanceSpacing = delta * multiplier;
|
int distanceSpacing = delta * multiplier;
|
||||||
|
|
||||||
|
// Condensing is when the graph will pull nodes closer together on the x axis to
|
||||||
|
// reduce whitespace and make the entire graph easier to see. In this case, update
|
||||||
|
// the offset to avoid running into the moved vertices.
|
||||||
|
|
||||||
// Condensing Note: we have guilty knowledge that our parent class my condense the
|
// Condensing Note: we have guilty knowledge that our parent class my condense the
|
||||||
// vertices and edges towards the center of the graph after we calculate positions.
|
// vertices and edges towards the center of the graph after we calculate positions.
|
||||||
// To prevent the edges from moving to far behind the vertices, we will compensate a
|
// To prevent the edges from moving to far behind the vertices, we will compensate a
|
||||||
// bit for that effect using this offset value. The getEdgeOffset() method is
|
// bit for that effect using this offset value. The getEdgeOffset() method is
|
||||||
// updated for the condense factor.
|
// updated for the condense factor.
|
||||||
|
|
||||||
int exaggerationFactor = 1;
|
int exaggerationFactor = 1;
|
||||||
if (isCondensedLayout()) {
|
if (isCondensedLayout()) {
|
||||||
exaggerationFactor = 2; // determined by trial-and-error; can be made into an option
|
exaggerationFactor = 2; // determined by trial-and-error; can be made into an option
|
||||||
|
@ -556,19 +623,6 @@ public class DecompilerNestedLayout extends AbstractFGLayout {
|
||||||
private void routeAroundColumnVertices(Vertex2d start, Vertex2d end,
|
private void routeAroundColumnVertices(Vertex2d start, Vertex2d end,
|
||||||
Vertex2dFactory vertex2dFactory, List<Point2D> articulations, double edgeX) {
|
Vertex2dFactory vertex2dFactory, List<Point2D> articulations, double edgeX) {
|
||||||
|
|
||||||
Column column = vertex2dFactory.getColumn(edgeX);
|
|
||||||
int columnIndex = 0;
|
|
||||||
if (column != null) {
|
|
||||||
// a null column happens with a negative x value that is outside of any column
|
|
||||||
columnIndex = column.index;
|
|
||||||
}
|
|
||||||
|
|
||||||
routeAroundColumnVertices(start, end, columnIndex, vertex2dFactory, articulations, edgeX);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void routeAroundColumnVertices(Vertex2d start, Vertex2d end, int column,
|
|
||||||
Vertex2dFactory vertex2dFactory, List<Point2D> articulations, double edgeX) {
|
|
||||||
|
|
||||||
if (useSimpleRouting()) {
|
if (useSimpleRouting()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -582,16 +636,36 @@ public class DecompilerNestedLayout extends AbstractFGLayout {
|
||||||
startRow = end.rowIndex;
|
startRow = end.rowIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int startColumn = Math.min(start.columnIndex, end.columnIndex);
|
||||||
|
int endColumn = Math.max(start.columnIndex, end.columnIndex);
|
||||||
|
if (goingDown) {
|
||||||
|
endRow -= 1;
|
||||||
|
endColumn -= 1;
|
||||||
|
|
||||||
|
if (start.columnIndex <= end.columnIndex) {
|
||||||
|
startRow += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// going up we swing out to the right; grab the column that is out to the right
|
||||||
|
Column rightColumn = vertex2dFactory.getColumn(edgeX);
|
||||||
|
endColumn = rightColumn.index;
|
||||||
|
}
|
||||||
|
|
||||||
List<Vertex2d> toCheck = new LinkedList<>();
|
List<Vertex2d> toCheck = new LinkedList<>();
|
||||||
for (int row = startRow + 1; row < endRow; row++) {
|
for (int row = startRow; row < endRow + 1; row++) {
|
||||||
|
|
||||||
|
for (int col = startColumn; col < endColumn + 1; col++) {
|
||||||
|
|
||||||
// assume any other vertex in our column can clip (it will not clip when
|
// assume any other vertex in our column can clip (it will not clip when
|
||||||
// the 'spacing' above pushes the edge away from this column, like for
|
// the 'spacing' above pushes the edge away from this column, like for
|
||||||
// large row delta values)
|
// large row delta values)
|
||||||
Vertex2d otherVertex = vertex2dFactory.get(row, column);
|
Vertex2d otherVertex = vertex2dFactory.get(row, col);
|
||||||
if (otherVertex != null) {
|
if (otherVertex != null) {
|
||||||
toCheck.add(otherVertex);
|
toCheck.add(otherVertex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// always process the vertices from the start vertex so that the articulation adjustments
|
// always process the vertices from the start vertex so that the articulation adjustments
|
||||||
// are correct
|
// are correct
|
||||||
|
@ -605,11 +679,16 @@ public class DecompilerNestedLayout extends AbstractFGLayout {
|
||||||
int padding = VERTEX_TO_EDGE_AVOIDANCE_PADDING;
|
int padding = VERTEX_TO_EDGE_AVOIDANCE_PADDING;
|
||||||
int distanceSpacing = padding + delta; // adding the delta makes overlap less likely
|
int distanceSpacing = padding + delta; // adding the delta makes overlap less likely
|
||||||
|
|
||||||
|
// Condensing is when the graph will pull nodes closer together on the x axis to
|
||||||
|
// reduce whitespace and make the entire graph easier to see. In this case, update
|
||||||
|
// the offset to avoid running into the moved vertices.
|
||||||
|
|
||||||
// Condensing Note: we have guilty knowledge that our parent class my condense the
|
// Condensing Note: we have guilty knowledge that our parent class my condense the
|
||||||
// vertices and edges towards the center of the graph after we calculate positions.
|
// vertices and edges towards the center of the graph after we calculate positions.
|
||||||
// To prevent the edges from moving to far behind the vertices, we will compensate a
|
// To prevent the edges from moving to far behind the vertices, we will compensate a
|
||||||
// bit for that effect using this offset value. The getEdgeOffset() method is
|
// bit for that effect using this offset value. The getEdgeOffset() method is
|
||||||
// updated for the condense factor.
|
// updated for the condense factor.
|
||||||
|
|
||||||
int vertexToEdgeOffset = otherVertex.getEdgeOffset();
|
int vertexToEdgeOffset = otherVertex.getEdgeOffset();
|
||||||
int exaggerationFactor = 1;
|
int exaggerationFactor = 1;
|
||||||
if (isCondensedLayout()) {
|
if (isCondensedLayout()) {
|
||||||
|
@ -696,15 +775,11 @@ public class DecompilerNestedLayout extends AbstractFGLayout {
|
||||||
return !getLayoutOptions().useEdgeRoutingAroundVertices();
|
return !getLayoutOptions().useEdgeRoutingAroundVertices();
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Point2D> routeLoopEdge(Vertex2d start, Vertex2d end, Column loopEndColumn) {
|
private List<Point2D> routeLoopEdge(Vertex2d start, Vertex2d end, double x) {
|
||||||
|
|
||||||
// going backwards
|
// going backwards
|
||||||
List<Point2D> articulations = new ArrayList<>();
|
List<Point2D> articulations = new ArrayList<>();
|
||||||
|
|
||||||
// loop first point - same y coord as the vertex; x is the middle of the next col
|
|
||||||
int halfWidth = loopEndColumn.getPaddedWidth(isCondensedLayout()) >> 1;
|
|
||||||
double x = loopEndColumn.x + halfWidth; // middle of the column
|
|
||||||
|
|
||||||
int startRow = start.rowIndex;
|
int startRow = start.rowIndex;
|
||||||
int endRow = end.rowIndex;
|
int endRow = end.rowIndex;
|
||||||
if (startRow > endRow) { // going upwards
|
if (startRow > endRow) { // going upwards
|
||||||
|
@ -733,27 +808,47 @@ public class DecompilerNestedLayout extends AbstractFGLayout {
|
||||||
|
|
||||||
private void lighten(FGEdge e) {
|
private void lighten(FGEdge e) {
|
||||||
|
|
||||||
|
if (!getLayoutOptions().useDimmedReturnEdges()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// assumption: edges that move to the left in this layout are return flows that happen
|
// assumption: edges that move to the left in this layout are return flows that happen
|
||||||
// after the code block has been executed. We dim those a bit so that they
|
// after the code block has been executed. We dim those a bit so that they
|
||||||
// produce less clutter.
|
// produce less clutter.
|
||||||
e.setDefaultAlpha(.25);
|
e.setDefaultAlpha(.25);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Column getOutermostCol(LayoutLocationMap<FGVertex, FGEdge> layoutLocations,
|
private FGVertex getRightmostVertex(LayoutLocationMap<FGVertex, FGEdge> layoutLocations,
|
||||||
Set<FGVertex> vertices) {
|
Vertex2dFactory vertex2dFactory, Set<FGVertex> vertices) {
|
||||||
|
|
||||||
Column outermost = null;
|
List<Vertex2d> points = new ArrayList<>();
|
||||||
for (FGVertex v : vertices) {
|
for (FGVertex v : vertices) {
|
||||||
Column col = layoutLocations.col(v);
|
Vertex2d v2d = vertex2dFactory.get(v);
|
||||||
if (outermost == null) {
|
points.add(v2d);
|
||||||
outermost = col;
|
}
|
||||||
|
|
||||||
|
FGVertex v = getRightmostVertex(points);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
private FGVertex getRightmostVertex(Collection<Vertex2d> points) {
|
||||||
|
|
||||||
|
Vertex2d rightmost = null;
|
||||||
|
for (Vertex2d v2d : points) {
|
||||||
|
if (rightmost == null) {
|
||||||
|
rightmost = v2d;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// the rightmost is that which extends furthest to the right
|
||||||
|
double current = rightmost.getRight();
|
||||||
|
double other = v2d.getRight();
|
||||||
|
if (other > current) {
|
||||||
|
rightmost = v2d;
|
||||||
}
|
}
|
||||||
else if (col.x > outermost.x) {
|
|
||||||
outermost = col;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return outermost;
|
return rightmost.v;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -840,8 +935,11 @@ public class DecompilerNestedLayout extends AbstractFGLayout {
|
||||||
BlockCopy copy = (BlockCopy) child;
|
BlockCopy copy = (BlockCopy) child;
|
||||||
|
|
||||||
StringBuilder buffy = new StringBuilder();
|
StringBuilder buffy = new StringBuilder();
|
||||||
buffy.append(printDepth(depth, depth + 1)).append(' ').append(ID).append(
|
buffy.append(printDepth(depth, depth + 1))
|
||||||
" plain - ").append(copy.getRef());
|
.append(' ')
|
||||||
|
.append(ID)
|
||||||
|
.append(" plain - ")
|
||||||
|
.append(copy.getRef());
|
||||||
|
|
||||||
debug(buffy.toString());
|
debug(buffy.toString());
|
||||||
}
|
}
|
||||||
|
@ -1207,8 +1305,7 @@ public class DecompilerNestedLayout extends AbstractFGLayout {
|
||||||
|
|
||||||
int row = startRow;
|
int row = startRow;
|
||||||
|
|
||||||
for (int i = 0; i < allChildren.size(); i++) {
|
for (DecompilerBlock block : allChildren) {
|
||||||
DecompilerBlock block = allChildren.get(i);
|
|
||||||
if (block instanceof DecompilerBlockGraph) {
|
if (block instanceof DecompilerBlockGraph) {
|
||||||
row = ((DecompilerBlockGraph) block).setRows(row);
|
row = ((DecompilerBlockGraph) block).setRows(row);
|
||||||
}
|
}
|
||||||
|
@ -1229,8 +1326,7 @@ public class DecompilerNestedLayout extends AbstractFGLayout {
|
||||||
String getChildrenString(int depth) {
|
String getChildrenString(int depth) {
|
||||||
StringBuilder buffy = new StringBuilder();
|
StringBuilder buffy = new StringBuilder();
|
||||||
int childCount = 0;
|
int childCount = 0;
|
||||||
for (int i = 0; i < allChildren.size(); i++) {
|
for (DecompilerBlock block : allChildren) {
|
||||||
DecompilerBlock block = allChildren.get(i);
|
|
||||||
if (block instanceof DecompilerBlockGraph) {
|
if (block instanceof DecompilerBlockGraph) {
|
||||||
|
|
||||||
String blockName = block.getName();
|
String blockName = block.getName();
|
||||||
|
@ -1447,9 +1543,8 @@ public class DecompilerNestedLayout extends AbstractFGLayout {
|
||||||
// The 'list' structure for children's nesting:
|
// The 'list' structure for children's nesting:
|
||||||
// -all nodes are at the same level
|
// -all nodes are at the same level
|
||||||
//
|
//
|
||||||
for (int i = 0; i < allChildren.size(); i++) {
|
for (DecompilerBlock block : allChildren) {
|
||||||
int column = col;
|
int column = col;
|
||||||
DecompilerBlock block = allChildren.get(i);
|
|
||||||
block.setCol(column);
|
block.setCol(column);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1477,8 +1572,7 @@ public class DecompilerNestedLayout extends AbstractFGLayout {
|
||||||
// -each successive condition is another level nested
|
// -each successive condition is another level nested
|
||||||
//
|
//
|
||||||
int column = col;
|
int column = col;
|
||||||
for (int i = 0; i < allChildren.size(); i++) {
|
for (DecompilerBlock block : allChildren) {
|
||||||
DecompilerBlock block = allChildren.get(i);
|
|
||||||
block.setCol(column);
|
block.setCol(column);
|
||||||
column++;
|
column++;
|
||||||
}
|
}
|
||||||
|
@ -1518,8 +1612,7 @@ public class DecompilerNestedLayout extends AbstractFGLayout {
|
||||||
// -all blocks nested
|
// -all blocks nested
|
||||||
//
|
//
|
||||||
int column = col + 1;
|
int column = col + 1;
|
||||||
for (int i = 0; i < allChildren.size(); i++) {
|
for (DecompilerBlock block : allChildren) {
|
||||||
DecompilerBlock block = allChildren.get(i);
|
|
||||||
block.setCol(column);
|
block.setCol(column);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,7 +52,7 @@ public class ServerAdmin implements GhidraLaunchable {
|
||||||
* The following properties may be set:
|
* The following properties may be set:
|
||||||
* <pre>
|
* <pre>
|
||||||
* UserAdmin.invocation - identifies the name of the application used when displaying usage text.
|
* UserAdmin.invocation - identifies the name of the application used when displaying usage text.
|
||||||
* UserAdmin.serverDir - identifies the server directory instead of passing on command line.
|
* UserAdmin.config - identifies the config file instead of passing on command line.
|
||||||
* </pre>
|
* </pre>
|
||||||
* @param args command line arguments
|
* @param args command line arguments
|
||||||
*/
|
*/
|
||||||
|
@ -75,22 +75,18 @@ public class ServerAdmin implements GhidraLaunchable {
|
||||||
* The following properties may be set:
|
* The following properties may be set:
|
||||||
* <pre>
|
* <pre>
|
||||||
* UserAdmin.invocation - identifies the name of the application used when displaying usage text.
|
* UserAdmin.invocation - identifies the name of the application used when displaying usage text.
|
||||||
* UserAdmin.serverDir - identifies the server directory instead of passing on command line.
|
* UserAdmin.config - identifies the config file instead of passing on command line.
|
||||||
* </pre>
|
* </pre>
|
||||||
* @param args command line arguments
|
* @param args command line arguments
|
||||||
*/
|
*/
|
||||||
public void execute(String[] args) {
|
public void execute(String[] args) {
|
||||||
|
|
||||||
File serverDir = null;
|
|
||||||
|
|
||||||
int ix = 0;
|
int ix = 0;
|
||||||
if (args.length != 0 && !args[0].startsWith("-")) {
|
|
||||||
serverDir = new File(args[ix++]);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
serverDir = getServerDirFromConfig();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
String configFilePath = args.length != 0 && !args[0].startsWith("-") ? args[ix++]
|
||||||
|
: System.getProperty(CONFIG_FILE_PROPERTY);
|
||||||
|
|
||||||
|
File serverDir = getServerDirFromConfig(configFilePath);
|
||||||
if (serverDir == null || (args.length - ix) == 0) {
|
if (serverDir == null || (args.length - ix) == 0) {
|
||||||
displayUsage("");
|
displayUsage("");
|
||||||
System.exit(-1);
|
System.exit(-1);
|
||||||
|
@ -105,9 +101,7 @@ public class ServerAdmin implements GhidraLaunchable {
|
||||||
System.exit(-1);
|
System.exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (propertyUsed) {
|
|
||||||
System.out.println("Using server directory: " + serverDir);
|
System.out.println("Using server directory: " + serverDir);
|
||||||
}
|
|
||||||
|
|
||||||
File userFile = new File(serverDir, UserManager.USER_PASSWORD_FILE);
|
File userFile = new File(serverDir, UserManager.USER_PASSWORD_FILE);
|
||||||
if (!serverDir.isDirectory() || !userFile.isFile()) {
|
if (!serverDir.isDirectory() || !userFile.isFile()) {
|
||||||
|
@ -423,13 +417,14 @@ public class ServerAdmin implements GhidraLaunchable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private File getServerDirFromConfig() {
|
private File getServerDirFromConfig(String configFilePath) {
|
||||||
String p = System.getProperty(CONFIG_FILE_PROPERTY);
|
System.out.println("Using config file: " + configFilePath);
|
||||||
if (p == null) {
|
|
||||||
|
if (configFilePath == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
propertyUsed = true;
|
|
||||||
File configFile = new File(p);
|
File configFile = new File(configFilePath);
|
||||||
|
|
||||||
if (!configFile.exists()) {
|
if (!configFile.exists()) {
|
||||||
System.out.println("Config file not found: " + configFile.getAbsolutePath());
|
System.out.println("Config file not found: " + configFile.getAbsolutePath());
|
||||||
|
@ -455,8 +450,9 @@ public class ServerAdmin implements GhidraLaunchable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
p = config.getProperty(SERVER_DIR_CONFIG_PROPERTY);
|
String p = config.getProperty(SERVER_DIR_CONFIG_PROPERTY);
|
||||||
if (p == null) {
|
if (p == null) {
|
||||||
|
System.out.println("Failed to find property: " + SERVER_DIR_CONFIG_PROPERTY);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
File dir = new File(p);
|
File dir = new File(p);
|
||||||
|
@ -482,8 +478,8 @@ public class ServerAdmin implements GhidraLaunchable {
|
||||||
}
|
}
|
||||||
String invocationName = System.getProperty(INVOCATION_NAME_PROPERTY);
|
String invocationName = System.getProperty(INVOCATION_NAME_PROPERTY);
|
||||||
System.err.println("Usage: " +
|
System.err.println("Usage: " +
|
||||||
(invocationName != null ? invocationName : "java " + UserAdmin.class.getName()) +
|
(invocationName != null ? invocationName : "java " + ServerAdmin.class.getName()) +
|
||||||
(propertyUsed ? "" : " <serverPath>") + " [<command>] [<command>] ...");
|
(invocationName != null ? "" : " <configPath>") + " [<command>] [<command>] ...");
|
||||||
System.err.println("\nSupported commands:");
|
System.err.println("\nSupported commands:");
|
||||||
System.err.println(" -add <sid> [--p]");
|
System.err.println(" -add <sid> [--p]");
|
||||||
System.err.println(
|
System.err.println(
|
||||||
|
|
|
@ -151,6 +151,10 @@ public class DockableComponent extends JPanel implements ContainerListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showContextMenu(MouseEvent e) {
|
private void showContextMenu(MouseEvent e) {
|
||||||
|
if (e.isConsumed()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Component component = e.getComponent();
|
Component component = e.getComponent();
|
||||||
if (component == null) {
|
if (component == null) {
|
||||||
return; // not sure this can happen
|
return; // not sure this can happen
|
||||||
|
|
|
@ -16,12 +16,12 @@
|
||||||
package docking.framework;
|
package docking.framework;
|
||||||
|
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
import generic.jar.ResourceFile;
|
import generic.jar.ResourceFile;
|
||||||
import ghidra.framework.ApplicationProperties;
|
import ghidra.framework.ApplicationProperties;
|
||||||
import ghidra.util.SystemUtilities;
|
import ghidra.util.SystemUtilities;
|
||||||
|
import util.CollectionUtils;
|
||||||
import utility.application.ApplicationLayout;
|
import utility.application.ApplicationLayout;
|
||||||
import utility.application.ApplicationUtilities;
|
import utility.application.ApplicationUtilities;
|
||||||
import utility.module.ModuleUtilities;
|
import utility.module.ModuleUtilities;
|
||||||
|
@ -34,16 +34,6 @@ public class DockingApplicationLayout extends ApplicationLayout {
|
||||||
|
|
||||||
private static final String NO_RELEASE_NAME = "NO_RELEASE";
|
private static final String NO_RELEASE_NAME = "NO_RELEASE";
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a new docking application layout object with the given name.
|
|
||||||
*
|
|
||||||
* @param name The name of the application.
|
|
||||||
* @throws FileNotFoundException if there was a problem getting a user directory.
|
|
||||||
*/
|
|
||||||
public DockingApplicationLayout(String name) throws FileNotFoundException {
|
|
||||||
this(name, "0.1");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new docking application layout object with the given name and version.
|
* Constructs a new docking application layout object with the given name and version.
|
||||||
*
|
*
|
||||||
|
@ -57,24 +47,31 @@ public class DockingApplicationLayout extends ApplicationLayout {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new docking application layout object with the given set of application
|
* Constructs a new docking application layout object with the given set of application
|
||||||
* properties.
|
* properties. The default Ghidra application root directory(s) will be used.
|
||||||
*
|
*
|
||||||
* @param applicationProperties The properties object that will be read system properties.
|
* @param applicationProperties The properties object that will be read system properties.
|
||||||
* @throws FileNotFoundException if there was a problem getting a user directory.
|
* @throws FileNotFoundException if there was a problem getting a user directory.
|
||||||
*/
|
*/
|
||||||
public DockingApplicationLayout(ApplicationProperties applicationProperties)
|
public DockingApplicationLayout(ApplicationProperties applicationProperties)
|
||||||
throws FileNotFoundException {
|
throws FileNotFoundException {
|
||||||
|
this(getDefaultApplicationRootDirs(), applicationProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new docking application layout object with the given set of application
|
||||||
|
* properties.
|
||||||
|
*
|
||||||
|
* @param applicationRootDirs list of application root directories which should be
|
||||||
|
* used to idenitfy modules and resources. The first entry will be treated as the
|
||||||
|
* installation root.
|
||||||
|
* @param applicationProperties The properties object that will be read system properties.
|
||||||
|
* @throws FileNotFoundException if there was a problem getting a user directory.
|
||||||
|
*/
|
||||||
|
public DockingApplicationLayout(Collection<ResourceFile> applicationRootDirs,
|
||||||
|
ApplicationProperties applicationProperties) throws FileNotFoundException {
|
||||||
|
|
||||||
this.applicationProperties = Objects.requireNonNull(applicationProperties);
|
this.applicationProperties = Objects.requireNonNull(applicationProperties);
|
||||||
|
this.applicationRootDirs = applicationRootDirs;
|
||||||
// Application root directories
|
|
||||||
if (SystemUtilities.isInDevelopmentMode()) {
|
|
||||||
applicationRootDirs = ApplicationUtilities.findDefaultApplicationRootDirs();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
applicationRootDirs = new ArrayList<>();
|
|
||||||
applicationRootDirs.add(new ResourceFile(System.getProperty("user.dir")));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Application installation directory
|
// Application installation directory
|
||||||
applicationInstallationDir = applicationRootDirs.iterator().next().getParentFile();
|
applicationInstallationDir = applicationRootDirs.iterator().next().getParentFile();
|
||||||
|
@ -97,4 +94,18 @@ public class DockingApplicationLayout extends ApplicationLayout {
|
||||||
applicationInstallationDir);
|
applicationInstallationDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the default list of Application directories. In repo-based
|
||||||
|
* development mode this includes the root Ghidra directory within each repo.
|
||||||
|
* When not in development mode, the requirement is that the current working
|
||||||
|
* directory correspond to the installation root. The first entry will be
|
||||||
|
* the primary root in both cases.
|
||||||
|
* @return root directories
|
||||||
|
*/
|
||||||
|
public static Collection<ResourceFile> getDefaultApplicationRootDirs() {
|
||||||
|
if (SystemUtilities.isInDevelopmentMode()) {
|
||||||
|
return ApplicationUtilities.findDefaultApplicationRootDirs();
|
||||||
|
}
|
||||||
|
return CollectionUtils.asList(new ResourceFile(System.getProperty("user.dir")));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -313,14 +313,7 @@ public abstract class AbstractVisualGraphLayout<V extends VisualVertex,
|
||||||
Map<V, Point2D> vertexLayoutLocations =
|
Map<V, Point2D> vertexLayoutLocations =
|
||||||
positionVerticesInLayoutSpace(transformer, vertices, layoutLocations);
|
positionVerticesInLayoutSpace(transformer, vertices, layoutLocations);
|
||||||
|
|
||||||
Map<E, List<Point2D>> edgeLayoutArticulationLocations =
|
Map<E, List<Point2D>> edgeLayoutArticulationLocations = new HashMap<>();
|
||||||
positionEdgeArticulationsInLayoutSpace(transformer, vertexLayoutLocations, edges,
|
|
||||||
layoutLocations);
|
|
||||||
|
|
||||||
// DEGUG triggers grid lines to be printed; useful for debugging
|
|
||||||
// VisualGraphRenderer.DEBUG_ROW_COL_MAP.put((Graph<?, ?>) visualGraph,
|
|
||||||
// layoutLocations.copy());
|
|
||||||
|
|
||||||
Rectangle graphBounds =
|
Rectangle graphBounds =
|
||||||
getTotalGraphSize(vertexLayoutLocations, edgeLayoutArticulationLocations, transformer);
|
getTotalGraphSize(vertexLayoutLocations, edgeLayoutArticulationLocations, transformer);
|
||||||
double centerX = graphBounds.getCenterX();
|
double centerX = graphBounds.getCenterX();
|
||||||
|
@ -332,6 +325,12 @@ public abstract class AbstractVisualGraphLayout<V extends VisualVertex,
|
||||||
centerX, centerY);
|
centerX, centerY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
edgeLayoutArticulationLocations = positionEdgeArticulationsInLayoutSpace(transformer,
|
||||||
|
vertexLayoutLocations, edges, layoutLocations);
|
||||||
|
|
||||||
|
// DEGUG triggers grid lines to be printed; useful for debugging
|
||||||
|
// VisualGraphRenderer.DEBUG_ROW_COL_MAP.put(this, layoutLocations.copy());
|
||||||
|
|
||||||
layoutLocations.dispose();
|
layoutLocations.dispose();
|
||||||
gridLocations.dispose();
|
gridLocations.dispose();
|
||||||
|
|
||||||
|
|
|
@ -22,8 +22,8 @@ import java.util.*;
|
||||||
import com.google.common.base.Function;
|
import com.google.common.base.Function;
|
||||||
|
|
||||||
import edu.uci.ics.jung.algorithms.layout.Layout;
|
import edu.uci.ics.jung.algorithms.layout.Layout;
|
||||||
import edu.uci.ics.jung.graph.Graph;
|
|
||||||
import edu.uci.ics.jung.visualization.*;
|
import edu.uci.ics.jung.visualization.*;
|
||||||
|
import edu.uci.ics.jung.visualization.layout.ObservableCachingLayout;
|
||||||
import edu.uci.ics.jung.visualization.renderers.Renderer;
|
import edu.uci.ics.jung.visualization.renderers.Renderer;
|
||||||
import edu.uci.ics.jung.visualization.transform.shape.GraphicsDecorator;
|
import edu.uci.ics.jung.visualization.transform.shape.GraphicsDecorator;
|
||||||
import ghidra.graph.viewer.*;
|
import ghidra.graph.viewer.*;
|
||||||
|
@ -44,7 +44,8 @@ public class VisualGraphRenderer<V extends VisualVertex, E extends VisualEdge<V>
|
||||||
/**
|
/**
|
||||||
* Used for displaying grid information for graph layouts
|
* Used for displaying grid information for graph layouts
|
||||||
*/
|
*/
|
||||||
public static Map<Graph<?, ?>, LayoutLocationMap<?, ?>> DEBUG_ROW_COL_MAP = new HashMap<>();
|
public static Map<VisualGraphLayout<?, ?>, LayoutLocationMap<?, ?>> DEBUG_ROW_COL_MAP =
|
||||||
|
new HashMap<>();
|
||||||
|
|
||||||
private Renderer.EdgeLabel<V, E> edgeLabelRenderer = new BasicEdgeLabelRenderer<>();
|
private Renderer.EdgeLabel<V, E> edgeLabelRenderer = new BasicEdgeLabelRenderer<>();
|
||||||
|
|
||||||
|
@ -122,11 +123,15 @@ public class VisualGraphRenderer<V extends VisualVertex, E extends VisualEdge<V>
|
||||||
edgeLabelRenderer.labelEdge(rc, layout, e, xform.apply(e));
|
edgeLabelRenderer.labelEdge(rc, layout, e, xform.apply(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings({ "unchecked", "rawtypes" }) // the types in the cast matter not
|
||||||
private void paintLayoutGridCells(RenderContext<V, E> renderContext, Layout<V, E> layout) {
|
private void paintLayoutGridCells(RenderContext<V, E> renderContext, Layout<V, E> layout) {
|
||||||
|
|
||||||
// to enable this debug, search java files for commented-out uses of 'DEBUG_ROW_COL_MAP'
|
// to enable this debug, search java files for commented-out uses of 'DEBUG_ROW_COL_MAP'
|
||||||
Graph<V, E> graph = layout.getGraph();
|
Layout<V, E> key = layout;
|
||||||
LayoutLocationMap<?, ?> locationMap = DEBUG_ROW_COL_MAP.get(graph);
|
if (layout instanceof ObservableCachingLayout) {
|
||||||
|
key = ((ObservableCachingLayout) layout).getDelegate();
|
||||||
|
}
|
||||||
|
LayoutLocationMap<?, ?> locationMap = DEBUG_ROW_COL_MAP.get(key);
|
||||||
if (locationMap == null) {
|
if (locationMap == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,6 @@ import ghidra.framework.model.ToolServices;
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
import ghidra.util.SystemUtilities;
|
import ghidra.util.SystemUtilities;
|
||||||
import ghidra.util.classfinder.ClassSearcher;
|
import ghidra.util.classfinder.ClassSearcher;
|
||||||
import ghidra.util.exception.AssertException;
|
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.CancelledException;
|
||||||
import ghidra.util.xml.GenericXMLOutputter;
|
import ghidra.util.xml.GenericXMLOutputter;
|
||||||
import ghidra.util.xml.XmlUtilities;
|
import ghidra.util.xml.XmlUtilities;
|
||||||
|
@ -52,7 +51,6 @@ public abstract class StandAloneApplication implements GenericStandAloneApplicat
|
||||||
/**
|
/**
|
||||||
* Creates a new application using the given properties filename. The
|
* Creates a new application using the given properties filename. The
|
||||||
* filename is expected reside in the current working directory.
|
* filename is expected reside in the current working directory.
|
||||||
*
|
|
||||||
* <p>
|
* <p>
|
||||||
* <b>The given properties file is expected to have the
|
* <b>The given properties file is expected to have the
|
||||||
* {@link ApplicationProperties#APPLICATION_NAME_PROPERTY} and
|
* {@link ApplicationProperties#APPLICATION_NAME_PROPERTY} and
|
||||||
|
@ -60,43 +58,59 @@ public abstract class StandAloneApplication implements GenericStandAloneApplicat
|
||||||
* set.</b>
|
* set.</b>
|
||||||
*
|
*
|
||||||
* @param propertiesFilename the name of the properties file.
|
* @param propertiesFilename the name of the properties file.
|
||||||
|
* @throws IOException error causing application initialization failure
|
||||||
*/
|
*/
|
||||||
public StandAloneApplication(String propertiesFilename) {
|
public StandAloneApplication(String propertiesFilename) throws IOException {
|
||||||
|
this(new DockingApplicationLayout(readApplicationProperties(propertiesFilename)));
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
/**
|
||||||
|
* Creates a new application using the specified application name
|
||||||
|
* and version.
|
||||||
|
* @param name application name
|
||||||
|
* @param version application version
|
||||||
|
* @throws IOException error causing application initialization failure
|
||||||
|
*/
|
||||||
|
public StandAloneApplication(String name, String version) throws IOException {
|
||||||
|
this(new DockingApplicationLayout(name, version));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* reates a new application using the given application layout
|
||||||
|
* and associated application properties.
|
||||||
|
* @param applicationLayout application layout
|
||||||
|
*/
|
||||||
|
public StandAloneApplication(ApplicationLayout applicationLayout) {
|
||||||
|
init(applicationLayout);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read {@link ApplicationProperties} from the specified file path relative
|
||||||
|
* to the current working directory.
|
||||||
|
* <p>
|
||||||
|
* <b>The given properties file is expected to have the
|
||||||
|
* {@link ApplicationProperties#APPLICATION_NAME_PROPERTY} and
|
||||||
|
* {@link ApplicationProperties#APPLICATION_VERSION_PROPERTY} properties
|
||||||
|
* set.</b>
|
||||||
|
* @param propertiesFilename the name of the properties file.
|
||||||
|
* @return application properties
|
||||||
|
* @throws IOException if file read error occurs
|
||||||
|
*/
|
||||||
|
public static ApplicationProperties readApplicationProperties(String propertiesFilename)
|
||||||
|
throws IOException {
|
||||||
ApplicationProperties properties = ApplicationProperties.fromFile(propertiesFilename);
|
ApplicationProperties properties = ApplicationProperties.fromFile(propertiesFilename);
|
||||||
String name = properties.getProperty(ApplicationProperties.APPLICATION_NAME_PROPERTY);
|
String name = properties.getProperty(ApplicationProperties.APPLICATION_NAME_PROPERTY);
|
||||||
if (name == null) {
|
if (name == null) {
|
||||||
Msg.error(this,
|
Msg.error(StandAloneApplication.class,
|
||||||
"The application.name property is not set in " + propertiesFilename);
|
"The application.name property is not set in " + propertiesFilename);
|
||||||
}
|
}
|
||||||
|
|
||||||
String version =
|
String version = properties.getProperty(ApplicationProperties.APPLICATION_VERSION_PROPERTY);
|
||||||
properties.getProperty(ApplicationProperties.APPLICATION_VERSION_PROPERTY);
|
|
||||||
if (version == null) {
|
if (version == null) {
|
||||||
Msg.error(this,
|
Msg.error(StandAloneApplication.class,
|
||||||
"The application.name property is not set in " + propertiesFilename);
|
"The application.name property is not set in " + propertiesFilename);
|
||||||
}
|
}
|
||||||
|
return properties;
|
||||||
ApplicationLayout applicationLayout = new DockingApplicationLayout(properties);
|
|
||||||
init(applicationLayout);
|
|
||||||
}
|
|
||||||
catch (IOException e) {
|
|
||||||
throw new AssertException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public StandAloneApplication(String name, String version) {
|
|
||||||
|
|
||||||
// Setup application layout
|
|
||||||
try {
|
|
||||||
ApplicationLayout applicationLayout = new DockingApplicationLayout(name, version);
|
|
||||||
init(applicationLayout);
|
|
||||||
}
|
|
||||||
catch (IOException e) {
|
|
||||||
throw new AssertException(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void init(ApplicationLayout applicationLayout) {
|
private void init(ApplicationLayout applicationLayout) {
|
||||||
|
|
|
@ -534,53 +534,7 @@ public class NamespaceUtils {
|
||||||
throws InvalidInputException {
|
throws InvalidInputException {
|
||||||
|
|
||||||
Symbol namespaceSymbol = namespace.getSymbol();
|
Symbol namespaceSymbol = namespace.getSymbol();
|
||||||
String name = namespaceSymbol.getName();
|
|
||||||
SourceType originalSource = namespaceSymbol.getSource();
|
|
||||||
|
|
||||||
SymbolTable symbolTable = namespaceSymbol.getProgram().getSymbolTable();
|
SymbolTable symbolTable = namespaceSymbol.getProgram().getSymbolTable();
|
||||||
|
return symbolTable.convertNamespaceToClass(namespace);
|
||||||
// Temporarily rename old namespace (it will be removed at the end)
|
|
||||||
int count = 1;
|
|
||||||
while (true) {
|
|
||||||
String n = name + "_" + count++;
|
|
||||||
try {
|
|
||||||
namespaceSymbol.setName(n, SourceType.ANALYSIS);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
catch (DuplicateNameException e) {
|
|
||||||
// continue
|
|
||||||
}
|
|
||||||
catch (InvalidInputException e) {
|
|
||||||
throw new AssertException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// create new class namespace
|
|
||||||
GhidraClass classNamespace = null;
|
|
||||||
try {
|
|
||||||
classNamespace =
|
|
||||||
symbolTable.createClass(namespace.getParentNamespace(), name, originalSource);
|
|
||||||
}
|
|
||||||
catch (DuplicateNameException e) {
|
|
||||||
throw new AssertException(e);
|
|
||||||
}
|
|
||||||
catch (InvalidInputException e) {
|
|
||||||
// The only cause of this exception can be assumed but we need to
|
|
||||||
// avoid showing the user a temporary name
|
|
||||||
throw new InvalidInputException(
|
|
||||||
"Namespace contained within Function may not be converted to a class: " + name);
|
|
||||||
}
|
|
||||||
|
|
||||||
// move everything from old namespace into new class namespace
|
|
||||||
try {
|
|
||||||
for (Symbol s : symbolTable.getSymbols(namespace)) {
|
|
||||||
s.setNamespace(classNamespace);
|
|
||||||
}
|
|
||||||
namespaceSymbol.delete();
|
|
||||||
}
|
|
||||||
catch (DuplicateNameException | InvalidInputException | CircularDependencyException e) {
|
|
||||||
throw new AssertException(e);
|
|
||||||
}
|
|
||||||
return classNamespace;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1695,6 +1695,9 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void disassociate(DataType dataType) {
|
public void disassociate(DataType dataType) {
|
||||||
|
|
||||||
|
lock.acquire();
|
||||||
|
try {
|
||||||
UniversalID oldDtID = dataType.getUniversalID();
|
UniversalID oldDtID = dataType.getUniversalID();
|
||||||
SourceArchive sourceArchive = dataType.getSourceArchive();
|
SourceArchive sourceArchive = dataType.getSourceArchive();
|
||||||
sourceArchive = resolveSourceArchive(sourceArchive);
|
sourceArchive = resolveSourceArchive(sourceArchive);
|
||||||
|
@ -1724,6 +1727,10 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
||||||
|
|
||||||
dataTypeChanged(dataType);
|
dataTypeChanged(dataType);
|
||||||
}
|
}
|
||||||
|
finally {
|
||||||
|
lock.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private Collection<DataType> filterOutNonSourceSettableDataTypes(
|
private Collection<DataType> filterOutNonSourceSettableDataTypes(
|
||||||
Collection<DataType> datatypes) {
|
Collection<DataType> datatypes) {
|
||||||
|
@ -2694,7 +2701,8 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
creatingDataType++;
|
creatingDataType++;
|
||||||
DBRecord record = functionDefAdapter.createRecord(name, funDef.getComment(), cat.getID(),
|
DBRecord record =
|
||||||
|
functionDefAdapter.createRecord(name, funDef.getComment(), cat.getID(),
|
||||||
DEFAULT_DATATYPE_ID, funDef.hasVarArgs(), funDef.getGenericCallingConvention(),
|
DEFAULT_DATATYPE_ID, funDef.hasVarArgs(), funDef.getGenericCallingConvention(),
|
||||||
sourceArchiveIdValue, universalIdValue, funDef.getLastChangeTime());
|
sourceArchiveIdValue, universalIdValue, funDef.getLastChangeTime());
|
||||||
FunctionDefinitionDB funDefDb =
|
FunctionDefinitionDB funDefDb =
|
||||||
|
@ -3696,8 +3704,14 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
||||||
@Override
|
@Override
|
||||||
public DataType getDataType(SourceArchive sourceArchive, UniversalID datatypeID) {
|
public DataType getDataType(SourceArchive sourceArchive, UniversalID datatypeID) {
|
||||||
UniversalID sourceID = sourceArchive == null ? null : sourceArchive.getSourceArchiveID();
|
UniversalID sourceID = sourceArchive == null ? null : sourceArchive.getSourceArchiveID();
|
||||||
|
lock.acquire();
|
||||||
|
try {
|
||||||
return idsToDataTypeMap.getDataType(sourceID, datatypeID);
|
return idsToDataTypeMap.getDataType(sourceID, datatypeID);
|
||||||
}
|
}
|
||||||
|
finally {
|
||||||
|
lock.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DataType findDataTypeForID(UniversalID datatypeID) {
|
public DataType findDataTypeForID(UniversalID datatypeID) {
|
||||||
|
@ -4162,7 +4176,11 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
||||||
|
|
||||||
Map<UniversalID, DataType> idMap =
|
Map<UniversalID, DataType> idMap =
|
||||||
map.computeIfAbsent(sourceID, k -> new ConcurrentHashMap<>());
|
map.computeIfAbsent(sourceID, k -> new ConcurrentHashMap<>());
|
||||||
final UniversalID sourceArchiveID = sourceID;
|
UniversalID sourceArchiveID = sourceID;
|
||||||
|
|
||||||
|
// note: this call is atomic and has a lock on the 'idMap'. It may call to a method
|
||||||
|
// that requires a db lock. As such, the call to computeIfAbsent() must be
|
||||||
|
// made while holding the db lock.
|
||||||
return idMap.computeIfAbsent(dataTypeID,
|
return idMap.computeIfAbsent(dataTypeID,
|
||||||
k -> findDataTypeForIDs(sourceArchiveID, dataTypeID));
|
k -> findDataTypeForIDs(sourceArchiveID, dataTypeID));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/* ###
|
/* ###
|
||||||
* IP: GHIDRA
|
* IP: GHIDRA
|
||||||
* REVIEWED: YES
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -19,8 +18,7 @@ package ghidra.program.database.symbol;
|
||||||
import ghidra.program.model.address.AddressSetView;
|
import ghidra.program.model.address.AddressSetView;
|
||||||
import ghidra.program.model.listing.CircularDependencyException;
|
import ghidra.program.model.listing.CircularDependencyException;
|
||||||
import ghidra.program.model.listing.GhidraClass;
|
import ghidra.program.model.listing.GhidraClass;
|
||||||
import ghidra.program.model.symbol.Namespace;
|
import ghidra.program.model.symbol.*;
|
||||||
import ghidra.program.model.symbol.Symbol;
|
|
||||||
import ghidra.util.exception.DuplicateNameException;
|
import ghidra.util.exception.DuplicateNameException;
|
||||||
import ghidra.util.exception.InvalidInputException;
|
import ghidra.util.exception.InvalidInputException;
|
||||||
|
|
||||||
|
@ -63,6 +61,19 @@ class GhidraClassDB implements GhidraClass {
|
||||||
return symbol.getName();
|
return symbol.getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setName(String name, SourceType source, boolean checkForDuplicates)
|
||||||
|
throws DuplicateNameException, InvalidInputException {
|
||||||
|
|
||||||
|
try {
|
||||||
|
symbol.doSetNameAndNamespace(name, symbol.getParentNamespace(), source,
|
||||||
|
checkForDuplicates);
|
||||||
|
}
|
||||||
|
catch (CircularDependencyException e) {
|
||||||
|
// can't happen since we are not changing the namespace
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see ghidra.program.model.symbol.Namespace#getID()
|
* @see ghidra.program.model.symbol.Namespace#getID()
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -104,7 +104,8 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
record = rec;
|
record = rec;
|
||||||
address = symbolMgr.getAddressMap().decodeAddress(
|
address = symbolMgr.getAddressMap()
|
||||||
|
.decodeAddress(
|
||||||
rec.getLongValue(SymbolDatabaseAdapter.SYMBOL_ADDR_COL));
|
rec.getLongValue(SymbolDatabaseAdapter.SYMBOL_ADDR_COL));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -522,8 +523,8 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
|
||||||
return source;
|
return source;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public void doSetNameAndNamespace(String newName, Namespace newNamespace, SourceType source,
|
||||||
public void setNameAndNamespace(String newName, Namespace newNamespace, SourceType source)
|
boolean checkForDuplicates)
|
||||||
throws DuplicateNameException, InvalidInputException, CircularDependencyException {
|
throws DuplicateNameException, InvalidInputException, CircularDependencyException {
|
||||||
|
|
||||||
lock.acquire();
|
lock.acquire();
|
||||||
|
@ -563,7 +564,11 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
|
||||||
if (!namespaceChange && !nameChange) {
|
if (!namespaceChange && !nameChange) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
symbolMgr.checkDuplicateSymbolName(address, newName, newNamespace, getSymbolType());
|
|
||||||
|
if (checkForDuplicates) {
|
||||||
|
symbolMgr.checkDuplicateSymbolName(address, newName, newNamespace,
|
||||||
|
getSymbolType());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (record != null) {
|
if (record != null) {
|
||||||
|
@ -617,6 +622,13 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setNameAndNamespace(String newName, Namespace newNamespace, SourceType source)
|
||||||
|
throws DuplicateNameException, InvalidInputException, CircularDependencyException {
|
||||||
|
|
||||||
|
doSetNameAndNamespace(newName, newNamespace, source, true);
|
||||||
|
}
|
||||||
|
|
||||||
protected List<SymbolDB> getSymbolsDynamicallyRenamedByMyRename() {
|
protected List<SymbolDB> getSymbolsDynamicallyRenamedByMyRename() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,6 @@ import ghidra.program.util.LanguageTranslator;
|
||||||
import ghidra.util.*;
|
import ghidra.util.*;
|
||||||
import ghidra.util.exception.*;
|
import ghidra.util.exception.*;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
import ghidra.util.task.TaskMonitorAdapter;
|
|
||||||
|
|
||||||
public class SymbolManager implements SymbolTable, ManagerDB {
|
public class SymbolManager implements SymbolTable, ManagerDB {
|
||||||
|
|
||||||
|
@ -128,7 +127,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
||||||
* Find previously defined variable storage address
|
* Find previously defined variable storage address
|
||||||
* @param storage variable storage
|
* @param storage variable storage
|
||||||
* @return previously defined variable storage address or null if not found
|
* @return previously defined variable storage address or null if not found
|
||||||
* @throws IOException
|
* @throws IOException if there is database exception
|
||||||
*/
|
*/
|
||||||
public Address findVariableStorageAddress(VariableStorage storage) throws IOException {
|
public Address findVariableStorageAddress(VariableStorage storage) throws IOException {
|
||||||
return variableStorageMgr.getVariableStorageAddress(storage, false);
|
return variableStorageMgr.getVariableStorageAddress(storage, false);
|
||||||
|
@ -183,7 +182,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
||||||
* where all the moved external addresses will be placed.
|
* where all the moved external addresses will be placed.
|
||||||
* The triggering of this upgrade relies on the addition of the VariableManager which
|
* The triggering of this upgrade relies on the addition of the VariableManager which
|
||||||
* trigger an upgrade.
|
* trigger an upgrade.
|
||||||
* @param monitor
|
* @param monitor the task monitor
|
||||||
*/
|
*/
|
||||||
private boolean upgradeOldNamespaceAddresses(TaskMonitor monitor)
|
private boolean upgradeOldNamespaceAddresses(TaskMonitor monitor)
|
||||||
throws IOException, CancelledException {
|
throws IOException, CancelledException {
|
||||||
|
@ -239,9 +238,9 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
||||||
/**
|
/**
|
||||||
* Upgrade old stack and register variable symbol address to variable addresses.
|
* Upgrade old stack and register variable symbol address to variable addresses.
|
||||||
* Also force associated references to be updated to new variable addresses.
|
* Also force associated references to be updated to new variable addresses.
|
||||||
* @param monitor
|
* @param monitor the task monitor
|
||||||
* @throws IOException
|
* @throws IOException if there is database exception
|
||||||
* @throws CancelledException
|
* @throws CancelledException if the operation is cancelled
|
||||||
*/
|
*/
|
||||||
private void processOldVariableAddresses(TaskMonitor monitor)
|
private void processOldVariableAddresses(TaskMonitor monitor)
|
||||||
throws IOException, CancelledException {
|
throws IOException, CancelledException {
|
||||||
|
@ -296,8 +295,8 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
||||||
* No more sharing the same variable address for multiple variable symbols.
|
* No more sharing the same variable address for multiple variable symbols.
|
||||||
* Must split these up. Only reference to variable addresses should be the
|
* Must split these up. Only reference to variable addresses should be the
|
||||||
* symbol address - reference refer to physical/stack addresses, and symbolIDs.
|
* symbol address - reference refer to physical/stack addresses, and symbolIDs.
|
||||||
* @param monitor
|
* @param monitor the task monitor
|
||||||
* @throws CancelledException
|
* @throws CancelledException if the operation is cancelled
|
||||||
*/
|
*/
|
||||||
public void migrateFromOldVariableStorageManager(TaskMonitor monitor)
|
public void migrateFromOldVariableStorageManager(TaskMonitor monitor)
|
||||||
throws CancelledException {
|
throws CancelledException {
|
||||||
|
@ -396,9 +395,8 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add old local symbols
|
* Add old local symbols
|
||||||
* @param table
|
* @throws IOException if there is database exception
|
||||||
* @throws IOException
|
* @throws CancelledException if the operation is cancelled
|
||||||
* @throws CancelledException
|
|
||||||
*/
|
*/
|
||||||
private void processOldLocalSymbols(TaskMonitor monitor)
|
private void processOldLocalSymbols(TaskMonitor monitor)
|
||||||
throws IOException, CancelledException {
|
throws IOException, CancelledException {
|
||||||
|
@ -450,6 +448,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
||||||
* @param oldAddr old address value from symbol table
|
* @param oldAddr old address value from symbol table
|
||||||
* @param name symbol name
|
* @param name symbol name
|
||||||
* @param isPrimary true if symbol is primary at oldAddr
|
* @param isPrimary true if symbol is primary at oldAddr
|
||||||
|
* @throws IOException if there is database exception
|
||||||
*/
|
*/
|
||||||
public static void saveLocalSymbol(DBHandle tmpHandle, long symbolID, long oldAddr, String name,
|
public static void saveLocalSymbol(DBHandle tmpHandle, long symbolID, long oldAddr, String name,
|
||||||
boolean isPrimary) throws IOException {
|
boolean isPrimary) throws IOException {
|
||||||
|
@ -480,18 +479,15 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Symbol> symbolList = getSymbols(name, namespace);
|
Symbol symbol = getFirstSymbol(name, namespace, s -> !s.getSymbolType().allowsDuplicates());
|
||||||
for (Symbol symbol : symbolList) {
|
if (symbol != null) {
|
||||||
if (!symbol.getSymbolType().allowsDuplicates()) {
|
|
||||||
throw new DuplicateNameException(
|
throw new DuplicateNameException(
|
||||||
"A " + symbol.getSymbolType() + " symbol with name " + name +
|
"A " + symbol.getSymbolType() + " symbol with name " + name +
|
||||||
" already exists in namespace " + symbol.getParentNamespace().getName());
|
" already exists in namespace " + symbol.getParentNamespace().getName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
/*
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert the specified dynamic symbol to a named symbol. Both symbol removed and symbol added
|
* Convert the specified dynamic symbol to a named symbol. Both symbol removed and symbol added
|
||||||
* notifications are performed, although the symbol instance is changed and continues to be
|
* notifications are performed, although the symbol instance is changed and continues to be
|
||||||
* valid.
|
* valid.
|
||||||
|
@ -509,7 +505,8 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
||||||
Address address = symbol.getAddress();
|
Address address = symbol.getAddress();
|
||||||
symbolRemoved(symbol, address, symbol.getName(), oldKey, Namespace.GLOBAL_NAMESPACE_ID,
|
symbolRemoved(symbol, address, symbol.getName(), oldKey, Namespace.GLOBAL_NAMESPACE_ID,
|
||||||
null);
|
null);
|
||||||
DBRecord record = adapter.createSymbol(newName, address, newParentID, SymbolType.LABEL, 0,
|
DBRecord record =
|
||||||
|
adapter.createSymbol(newName, address, newParentID, SymbolType.LABEL, 0,
|
||||||
1, null, source);
|
1, null, source);
|
||||||
symbol.setRecord(record);// symbol object was morphed
|
symbol.setRecord(record);// symbol object was morphed
|
||||||
symbolAdded(symbol);
|
symbolAdded(symbol);
|
||||||
|
@ -987,10 +984,11 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
||||||
return searchSymbolsByNamespaceFirst(name, namespace);
|
return searchSymbolsByNamespaceFirst(name, namespace);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to find the symbols by searching through all the symbols with the given name and including
|
// Try to find the symbols by searching through all the symbols with the given name
|
||||||
// only those in the specified namespace. If there are too many symbols with the same name and
|
// and including only those in the specified namespace. If there are too many symbols
|
||||||
// we are not in the global space, abandon this approach and instead search through all
|
// with the same name and we are not in the global space, abandon this approach and
|
||||||
// the symbols in the namespace and only include those with the specified name.
|
// instead search through all the symbols in the namespace and only include those with
|
||||||
|
// the specified name.
|
||||||
int count = 0;
|
int count = 0;
|
||||||
List<Symbol> list = new ArrayList<>();
|
List<Symbol> list = new ArrayList<>();
|
||||||
SymbolIterator symbols = getSymbols(name);
|
SymbolIterator symbols = getSymbols(name);
|
||||||
|
@ -1009,6 +1007,42 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// note: this could be public; adding it may be confusing due to the potential for having
|
||||||
|
// multiple symbols and not knowing when to call which method.
|
||||||
|
private Symbol getFirstSymbol(String name, Namespace namespace, Predicate<Symbol> test) {
|
||||||
|
if (namespace == null) {
|
||||||
|
namespace = namespaceMgr.getGlobalNamespace();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (namespace.isExternal() &&
|
||||||
|
SymbolUtilities.isReservedExternalDefaultName(name, program.getAddressFactory())) {
|
||||||
|
return findFirstSymbol(name, namespace, test);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (namespace instanceof Function && hasDefaultVariablePrefix(name)) {
|
||||||
|
return findFirstSymbol(name, namespace, test);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to find the symbols by searching through all the symbols with the given name
|
||||||
|
// and including only those in the specified namespace. If there are too many symbols
|
||||||
|
// with the same name and we are not in the global space, abandon this approach and
|
||||||
|
// instead search through all the symbols in the namespace and only include those with
|
||||||
|
// the specified name.
|
||||||
|
int count = 0;
|
||||||
|
SymbolIterator symbols = getSymbols(name);
|
||||||
|
for (Symbol s : symbols) {
|
||||||
|
if (++count == MAX_DUPLICATE_COUNT && !namespace.isGlobal()) {
|
||||||
|
return findFirstSymbol(name, namespace, test);
|
||||||
|
}
|
||||||
|
if (s.getParentNamespace().equals(namespace) &&
|
||||||
|
test.test(s)) {
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the list of symbols with the given name and namespace.
|
* Returns the list of symbols with the given name and namespace.
|
||||||
*
|
*
|
||||||
|
@ -1143,7 +1177,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the next available external symbol address
|
* Returns the next available external symbol address
|
||||||
* @return
|
* @return the address
|
||||||
*/
|
*/
|
||||||
public Address getNextExternalSymbolAddress() {
|
public Address getNextExternalSymbolAddress() {
|
||||||
int extID = 1;
|
int extID = 1;
|
||||||
|
@ -1414,6 +1448,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
||||||
if (!symbol.isDynamic()) {
|
if (!symbol.isDynamic()) {
|
||||||
createLabelHistoryRecord(addr, oldName, newName, LabelHistory.RENAME);
|
createLabelHistoryRecord(addr, oldName, newName, LabelHistory.RENAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
program.symbolChanged(symbol, ChangeManager.DOCR_SYMBOL_RENAMED, addr, symbol, oldName,
|
program.symbolChanged(symbol, ChangeManager.DOCR_SYMBOL_RENAMED, addr, symbol, oldName,
|
||||||
newName);
|
newName);
|
||||||
}
|
}
|
||||||
|
@ -1493,7 +1528,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
||||||
|
|
||||||
// fire event
|
// fire event
|
||||||
program.symbolChanged(symbol, ChangeManager.DOCR_SYMBOL_REMOVED, addr, symbol, name,
|
program.symbolChanged(symbol, ChangeManager.DOCR_SYMBOL_REMOVED, addr, symbol, name,
|
||||||
new Long(symbolID));
|
symbolID);
|
||||||
}
|
}
|
||||||
|
|
||||||
void externalEntryPointRemoved(Address addr) {
|
void externalEntryPointRemoved(Address addr) {
|
||||||
|
@ -1543,11 +1578,6 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
||||||
|
|
||||||
Symbol sym;
|
Symbol sym;
|
||||||
|
|
||||||
/**
|
|
||||||
* Construct iterator which returns a single symbol
|
|
||||||
*
|
|
||||||
* @param addr
|
|
||||||
*/
|
|
||||||
SingleSymbolIterator(Symbol sym) {
|
SingleSymbolIterator(Symbol sym) {
|
||||||
this.sym = sym;
|
this.sym = sym;
|
||||||
}
|
}
|
||||||
|
@ -2175,8 +2205,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
||||||
|
|
||||||
void moveLabelHistory(Address oldAddress, Address address) {
|
void moveLabelHistory(Address oldAddress, Address address) {
|
||||||
try {
|
try {
|
||||||
historyAdapter.moveAddressRange(oldAddress, address, 1, addrMap,
|
historyAdapter.moveAddressRange(oldAddress, address, 1, addrMap, TaskMonitor.DUMMY);
|
||||||
TaskMonitorAdapter.DUMMY_MONITOR);
|
|
||||||
}
|
}
|
||||||
catch (CancelledException e) {
|
catch (CancelledException e) {
|
||||||
// can't happen, used dummy monitor
|
// can't happen, used dummy monitor
|
||||||
|
@ -2266,6 +2295,109 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
||||||
return new NamespaceDB(s, namespaceMgr);
|
return new NamespaceDB(s, namespaceMgr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GhidraClass convertNamespaceToClass(Namespace namespace) {
|
||||||
|
|
||||||
|
if (namespace instanceof GhidraClass) {
|
||||||
|
return (GhidraClass) namespace;
|
||||||
|
}
|
||||||
|
|
||||||
|
lock.acquire();
|
||||||
|
try {
|
||||||
|
|
||||||
|
checkIsValidNamespaceForMyProgram(namespace);
|
||||||
|
|
||||||
|
Symbol namespaceSymbol = namespace.getSymbol();
|
||||||
|
String name = namespaceSymbol.getName();
|
||||||
|
SourceType originalSource = namespaceSymbol.getSource();
|
||||||
|
|
||||||
|
// no duplicate check, since this class name will be set to that of the existing namespace
|
||||||
|
String tempName = name + System.nanoTime();
|
||||||
|
SymbolDB classSymbol =
|
||||||
|
doCreateSpecialSymbol(Address.NO_ADDRESS, tempName, namespace.getParentNamespace(),
|
||||||
|
SymbolType.CLASS, -1, -1, null, originalSource, false /*check for duplicate */);
|
||||||
|
GhidraClassDB classNamespace = new GhidraClassDB(classSymbol, namespaceMgr);
|
||||||
|
|
||||||
|
// move everything from old namespace into new class namespace
|
||||||
|
for (Symbol s : getSymbols(namespace)) {
|
||||||
|
|
||||||
|
// no duplicate check, since these symbols all lived under the existing namespace
|
||||||
|
((SymbolDB) s).doSetNameAndNamespace(s.getName(), classNamespace, s.getSource(),
|
||||||
|
false /*check for duplicate */);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespaceSymbol.delete();
|
||||||
|
|
||||||
|
// fix name now that the old namespace is deleted
|
||||||
|
classNamespace.setName(name, SourceType.ANALYSIS, false /*check for duplicate */);
|
||||||
|
|
||||||
|
return classNamespace;
|
||||||
|
}
|
||||||
|
catch (DuplicateNameException | InvalidInputException | CircularDependencyException e) {
|
||||||
|
throw new AssertException("Unexpected exception creating class from namespace", e);
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
lock.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkIsValidNamespaceForMyProgram(Namespace namespace) {
|
||||||
|
|
||||||
|
if (namespace == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (namespace == program.getGlobalNamespace()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(namespace instanceof NamespaceDB)) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Namespace is not a valid parent for symbols: " +
|
||||||
|
namespace.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
SymbolDB dbSymbol = (SymbolDB) namespace.getSymbol();
|
||||||
|
if (program != dbSymbol.getProgram()) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Namespace symbol is from a different program");
|
||||||
|
}
|
||||||
|
|
||||||
|
// may throw a ConcurrentModificationException
|
||||||
|
dbSymbol.checkDeleted();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Namespace getOrCreateNameSpace(Namespace parent, String name, SourceType source)
|
||||||
|
throws DuplicateNameException, InvalidInputException {
|
||||||
|
|
||||||
|
lock.acquire();
|
||||||
|
try {
|
||||||
|
|
||||||
|
checkIsValidNamespaceForMyProgram(parent);
|
||||||
|
|
||||||
|
Symbol namespaceSymbol = getFirstSymbol(name, parent, s -> {
|
||||||
|
return s.getSymbolType() == SymbolType.NAMESPACE ||
|
||||||
|
s.getSymbolType() == SymbolType.CLASS;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (namespaceSymbol != null) {
|
||||||
|
return (Namespace) namespaceSymbol.getObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note: We know there are no namespaces with the name; do we still have to check for
|
||||||
|
// duplicates? Assuming yes, as another symbol type may exist with this name.
|
||||||
|
SymbolDB s =
|
||||||
|
doCreateSpecialSymbol(Address.NO_ADDRESS, name, parent, SymbolType.NAMESPACE, -1,
|
||||||
|
-1, null, source, true /*check for duplicates*/);
|
||||||
|
return new NamespaceDB(s, namespaceMgr);
|
||||||
|
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
lock.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Symbol createSymbolPlaceholder(Address address, long id) {
|
public Symbol createSymbolPlaceholder(Address address, long id) {
|
||||||
return SymbolDB.createSymbolPlaceholder(this, address, id);
|
return SymbolDB.createSymbolPlaceholder(this, address, id);
|
||||||
|
@ -2293,12 +2425,24 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
||||||
SymbolType symbolType, long data1, int data2, String data3, SourceType source)
|
SymbolType symbolType, long data1, int data2, String data3, SourceType source)
|
||||||
throws DuplicateNameException, InvalidInputException {
|
throws DuplicateNameException, InvalidInputException {
|
||||||
|
|
||||||
|
return doCreateSpecialSymbol(addr, name, parent, symbolType, data1, data2, data3, source,
|
||||||
|
true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private SymbolDB doCreateSpecialSymbol(Address addr, String name, Namespace parent,
|
||||||
|
SymbolType symbolType, long data1, int data2, String data3, SourceType source,
|
||||||
|
boolean checkForDuplicates)
|
||||||
|
throws DuplicateNameException, InvalidInputException {
|
||||||
|
|
||||||
lock.acquire();
|
lock.acquire();
|
||||||
try {
|
try {
|
||||||
parent = validateNamespace(parent, addr, symbolType);
|
parent = validateNamespace(parent, addr, symbolType);
|
||||||
source = validateSource(source, name, addr, symbolType);
|
source = validateSource(source, name, addr, symbolType);
|
||||||
name = validateName(name, source);
|
name = validateName(name, source);
|
||||||
|
|
||||||
|
if (checkForDuplicates) {
|
||||||
checkDuplicateSymbolName(addr, name, parent, symbolType);
|
checkDuplicateSymbolName(addr, name, parent, symbolType);
|
||||||
|
}
|
||||||
|
|
||||||
return doCreateSymbol(name, addr, parent, symbolType, data1, data2, data3, source);
|
return doCreateSymbol(name, addr, parent, symbolType, data1, data2, data3, source);
|
||||||
}
|
}
|
||||||
|
@ -2378,7 +2522,8 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal method for creating funcions symbols.
|
* Internal method for creating function symbols
|
||||||
|
*
|
||||||
* @param addr the address for the new symbol
|
* @param addr the address for the new symbol
|
||||||
* @param name the name of the new symbol
|
* @param name the name of the new symbol
|
||||||
* @param namespace the namespace for the new symbol
|
* @param namespace the namespace for the new symbol
|
||||||
|
@ -2489,7 +2634,8 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
||||||
long data1, int data2, String data3, SourceType source) {
|
long data1, int data2, String data3, SourceType source) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
DBRecord record = adapter.createSymbol(name, addr, namespace.getID(), type, data1, data2,
|
DBRecord record =
|
||||||
|
adapter.createSymbol(name, addr, namespace.getID(), type, data1, data2,
|
||||||
data3, source);
|
data3, source);
|
||||||
|
|
||||||
SymbolDB newSymbol = makeSymbol(addr, record, type);
|
SymbolDB newSymbol = makeSymbol(addr, record, type);
|
||||||
|
@ -2633,19 +2779,29 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Symbol getVariableSymbol(String name, Function function) {
|
public Symbol getVariableSymbol(String name, Function function) {
|
||||||
return findFirstSymbol(name, function, s -> {
|
return getFirstSymbol(name, function, s -> {
|
||||||
SymbolType t = s.getSymbolType();
|
SymbolType t = s.getSymbolType();
|
||||||
return t == SymbolType.PARAMETER || t == SymbolType.LOCAL_VAR;
|
return t == SymbolType.PARAMETER || t == SymbolType.LOCAL_VAR;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private Symbol getSpecificSymbol(String name, Namespace namespace, SymbolType type) {
|
private Symbol getSpecificSymbol(String name, Namespace namespace, SymbolType type) {
|
||||||
return findFirstSymbol(name, namespace, s -> s.getSymbolType() == type);
|
return getFirstSymbol(name, namespace, s -> s.getSymbolType() == type);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Symbol findFirstSymbol(String name, Namespace namespace, Predicate<Symbol> test) {
|
private Symbol findFirstSymbol(String name, Namespace namespace, Predicate<Symbol> test) {
|
||||||
List<Symbol> symbols = getSymbols(name, namespace);
|
if (namespace == null) {
|
||||||
return symbols.stream().filter(test).findFirst().orElse(null);
|
namespace = namespaceMgr.getGlobalNamespace();
|
||||||
|
}
|
||||||
|
|
||||||
|
SymbolIterator it = getSymbols(namespace);
|
||||||
|
while (it.hasNext()) {
|
||||||
|
Symbol s = it.next();
|
||||||
|
if (s.getName().equals(name) && test.test(s)) {
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,8 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.program.model.symbol;
|
package ghidra.program.model.symbol;
|
||||||
|
|
||||||
import java.util.Iterator;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.listing.*;
|
import ghidra.program.model.listing.*;
|
||||||
|
@ -504,7 +503,7 @@ public interface SymbolTable {
|
||||||
* @param name name of the namespace
|
* @param name name of the namespace
|
||||||
* @param source the source of this class namespace's symbol
|
* @param source the source of this class namespace's symbol
|
||||||
* @return new class namespace
|
* @return new class namespace
|
||||||
* @throws DuplicateNameException thrown if another non function or lable symbol exists with the given name
|
* @throws DuplicateNameException thrown if another non function or label symbol exists with the given name
|
||||||
* @throws InvalidInputException throw if the name has invalid characters or is null
|
* @throws InvalidInputException throw if the name has invalid characters or is null
|
||||||
* @throws IllegalArgumentException if you try to set the source to 'Symbol.DEFAULT'.
|
* @throws IllegalArgumentException if you try to set the source to 'Symbol.DEFAULT'.
|
||||||
*/
|
*/
|
||||||
|
@ -523,7 +522,7 @@ public interface SymbolTable {
|
||||||
* @param source the source of this external library's symbol
|
* @param source the source of this external library's symbol
|
||||||
* @return the new Library namespace.
|
* @return the new Library namespace.
|
||||||
* @throws IllegalArgumentException if you try to set the source to 'Symbol.DEFAULT'.
|
* @throws IllegalArgumentException if you try to set the source to 'Symbol.DEFAULT'.
|
||||||
* @throws DuplicateNameException thrown if another non function or lable symbol exists with the given name
|
* @throws DuplicateNameException thrown if another non function or label symbol exists with the given name
|
||||||
*/
|
*/
|
||||||
public Library createExternalLibrary(String name, SourceType source)
|
public Library createExternalLibrary(String name, SourceType source)
|
||||||
throws DuplicateNameException, InvalidInputException;
|
throws DuplicateNameException, InvalidInputException;
|
||||||
|
@ -534,7 +533,7 @@ public interface SymbolTable {
|
||||||
* @param name the name of the new namespace
|
* @param name the name of the new namespace
|
||||||
* @param source the source of this namespace's symbol
|
* @param source the source of this namespace's symbol
|
||||||
* @return the new Namespace object.
|
* @return the new Namespace object.
|
||||||
* @throws DuplicateNameException thrown if another non function or lable symbol exists with the given name
|
* @throws DuplicateNameException thrown if another non function or label symbol exists with the given name
|
||||||
* @throws InvalidInputException if the name is invalid.
|
* @throws InvalidInputException if the name is invalid.
|
||||||
* @throws IllegalArgumentException if you try to set the source to 'Symbol.DEFAULT'.
|
* @throws IllegalArgumentException if you try to set the source to 'Symbol.DEFAULT'.
|
||||||
*/
|
*/
|
||||||
|
@ -552,4 +551,32 @@ public interface SymbolTable {
|
||||||
*/
|
*/
|
||||||
public Symbol createSymbolPlaceholder(Address address, long id);
|
public Symbol createSymbolPlaceholder(Address address, long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the given namespace to a class namespace
|
||||||
|
*
|
||||||
|
* @param namespace the namespace to convert
|
||||||
|
* @return the new class
|
||||||
|
* @throws IllegalArgumentException if the given parent namespace is from a different program
|
||||||
|
* than that of this symbol table
|
||||||
|
* @throws ConcurrentModificationException if the given parent namespace has been deleted
|
||||||
|
*/
|
||||||
|
public GhidraClass convertNamespaceToClass(Namespace namespace);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets an existing namespace with the given name in the given parent. If no namespace exists,
|
||||||
|
* then one will be created.
|
||||||
|
*
|
||||||
|
* @param parent the parent namespace
|
||||||
|
* @param name the namespace name
|
||||||
|
* @param source the source type for the namespace if one is created
|
||||||
|
* @return the namespace
|
||||||
|
* @throws DuplicateNameException thrown if another non function or label symbol exists with
|
||||||
|
* the given name
|
||||||
|
* @throws InvalidInputException if the name is invalid
|
||||||
|
* @throws IllegalArgumentException if the given parent namespace is from a different program
|
||||||
|
* than that of this symbol table
|
||||||
|
* @throws ConcurrentModificationException if the given parent namespace has been deleted
|
||||||
|
*/
|
||||||
|
public Namespace getOrCreateNameSpace(Namespace parent, String name, SourceType source)
|
||||||
|
throws DuplicateNameException, InvalidInputException;
|
||||||
}
|
}
|
||||||
|
|
|
@ -518,15 +518,15 @@ N_0t_dbr1: @^N_0^"+,"^DBR is N_0 & DBR { export N_0; }
|
||||||
|
|
||||||
N_0t_bank1: @^N_0^"+" is N_0 { export N_0; }
|
N_0t_bank1: @^N_0^"+" is N_0 { export N_0; }
|
||||||
|
|
||||||
FR0_t: fr0 is OP_0 & fr0 { x:4 = 0; export x; } # dummy export, just looking for the display
|
FR0_t: fr0 is OP_0 & fr0 { export fr0; }
|
||||||
|
|
||||||
XMTRX_t: "xmtrx" is OP_0 { x:4 = 0; export x; } # dummy export, just looking for the display
|
XMTRX_t: "xmtrx" is OP_0 { x:4 = 0; export x; } # dummy export, just looking for the display
|
||||||
|
|
||||||
mach_t: MACH is OP_0 & MACH { x:4 = 0; export x; } # dummy export, just looking for the display
|
mach_t: MACH is OP_0 & MACH { export MACH; }
|
||||||
|
|
||||||
macl_t: MACL is OP_0 & MACL { x:4 = 0; export x; } # dummy export, just looking for the display
|
macl_t: MACL is OP_0 & MACL { export MACL; }
|
||||||
|
|
||||||
fpul_t: FPUL is OP_0 & FPUL { x:4 = 0; export x; } # dummy export, just looking for the display
|
fpul_t: FPUL is OP_0 & FPUL { export FPUL; }
|
||||||
|
|
||||||
fpscr_t: "FPSCR" is OP_0 { x:4 = 0; export x; } # dummy export, just looking for the display
|
fpscr_t: "FPSCR" is OP_0 { x:4 = 0; export x; } # dummy export, just looking for the display
|
||||||
|
|
||||||
|
|
|
@ -45,8 +45,8 @@ fi
|
||||||
OWNER="$(grep '^wrapper.app.account=' "${CONFIG}" | sed -e 's/^.*=\(.*\)\s*.*$/\1/')"
|
OWNER="$(grep '^wrapper.app.account=' "${CONFIG}" | sed -e 's/^.*=\(.*\)\s*.*$/\1/')"
|
||||||
|
|
||||||
if [ -z "${OWNER}" -o "${OWNER}" = "$(whoami)" ]; then
|
if [ -z "${OWNER}" -o "${OWNER}" = "$(whoami)" ]; then
|
||||||
VMARGS="-DUserAdmin.invocation=$(basename "${SCRIPT_FILE}") -DUserAdmin.config=\"${CONFIG}\""
|
VMARGS="-DUserAdmin.invocation=$(basename "${SCRIPT_FILE}")"
|
||||||
"${SCRIPT_DIR}"/../support/launch.sh fg svrAdmin "${MAXMEM}" "$VMARGS" ghidra.server.ServerAdmin "$@"
|
"${SCRIPT_DIR}"/../support/launch.sh fg svrAdmin "${MAXMEM}" "$VMARGS" ghidra.server.ServerAdmin "${CONFIG}" "$@"
|
||||||
else
|
else
|
||||||
echo "Running svrAdmin with $SUDO as ${OWNER} ..."
|
echo "Running svrAdmin with $SUDO as ${OWNER} ..."
|
||||||
$SUDO -u $OWNER "$0" "$@"
|
$SUDO -u $OWNER "$0" "$@"
|
||||||
|
|
|
@ -25,7 +25,7 @@ if [ ! -d "${GHIDRA_ROOT_DIR}" ]; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Set required VMARGS for jar builder application
|
# Set required VMARGS for jar builder application
|
||||||
APP_VMARGS="-DGhidraJarBuilder.Name=$(basename "${SCRIPT_FILE}") -DGhidra.Install.Root.Dir=\"${GHIDRA_ROOT_DIR}\" "
|
APP_VMARGS="-DGhidraJarBuilder.Name=$(basename "${SCRIPT_FILE}")"
|
||||||
|
|
||||||
# Launch jar builder
|
# Launch jar builder
|
||||||
"${SCRIPT_DIR}"/launch.sh "${LAUNCH_MODE}" Ghidra "${MAXMEM}" "${APP_VMARGS}" ghidra.util.GhidraJarBuilder -main ghidra.JarRun "$@"
|
"${SCRIPT_DIR}"/launch.sh "${LAUNCH_MODE}" Ghidra "${MAXMEM}" "${APP_VMARGS}" ghidra.util.GhidraJarBuilder -main ghidra.JarRun "$@"
|
||||||
|
|
|
@ -11,7 +11,7 @@ rem runtime which has been configured into the system PATH ahead of other Java
|
||||||
rem it may be necessary to explicitly specify the path to the installation by setting JAVA_HOME
|
rem it may be necessary to explicitly specify the path to the installation by setting JAVA_HOME
|
||||||
rem below:
|
rem below:
|
||||||
|
|
||||||
rem set JAVA_HOME=
|
rem set "JAVA_HOME="
|
||||||
|
|
||||||
setlocal enabledelayedexpansion
|
setlocal enabledelayedexpansion
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ if "%IS_ADMIN%"=="NO" (
|
||||||
|
|
||||||
rem Find the script directory
|
rem Find the script directory
|
||||||
rem %~dsp0 is location of current script under NT
|
rem %~dsp0 is location of current script under NT
|
||||||
set _REALPATH=%~dp0
|
set "_REALPATH=%~dp0"
|
||||||
|
|
||||||
set APP_NAME=ghidraSvr
|
set APP_NAME=ghidraSvr
|
||||||
set APP_LONG_NAME=Ghidra Server
|
set APP_LONG_NAME=Ghidra Server
|
||||||
|
@ -64,26 +64,26 @@ if exist "%_REALPATH%..\Ghidra\" goto normal
|
||||||
rem NOTE: If adjusting JAVA command assignment - do not attempt to add parameters (e.g., -d64, -version:1.7, etc.)
|
rem NOTE: If adjusting JAVA command assignment - do not attempt to add parameters (e.g., -d64, -version:1.7, etc.)
|
||||||
|
|
||||||
rem Development Environment
|
rem Development Environment
|
||||||
set GHIDRA_HOME=%_REALPATH%..\..\..\..
|
set "GHIDRA_HOME=%_REALPATH%..\..\..\.."
|
||||||
set WRAPPER_CONF=%_REALPATH%..\..\Common\server\server.conf
|
set "WRAPPER_CONF=%_REALPATH%..\..\Common\server\server.conf"
|
||||||
set DATA_DIR=%GHIDRA_HOME%\%MODULE_DIR%\build\data
|
set "DATA_DIR=%GHIDRA_HOME%\%MODULE_DIR%\build\data"
|
||||||
set CLASSPATH_FRAG=%GHIDRA_HOME%\%MODULE_DIR%\build\dev-meta\classpath.frag
|
set "CLASSPATH_FRAG=%GHIDRA_HOME%\%MODULE_DIR%\build\dev-meta\classpath.frag"
|
||||||
set LS_CPATH=%GHIDRA_HOME%\GhidraBuild\LaunchSupport\bin\main
|
set "LS_CPATH=%GHIDRA_HOME%\GhidraBuild\LaunchSupport\bin\main"
|
||||||
|
|
||||||
goto lab1
|
goto lab1
|
||||||
|
|
||||||
:normal
|
:normal
|
||||||
set GHIDRA_HOME=%_REALPATH%..
|
set "GHIDRA_HOME=%_REALPATH%.."
|
||||||
set WRAPPER_CONF=%_REALPATH%server.conf
|
set "WRAPPER_CONF=%_REALPATH%server.conf"
|
||||||
set DATA_DIR=%GHIDRA_HOME%\%MODULE_DIR%\data
|
set "DATA_DIR=%GHIDRA_HOME%\%MODULE_DIR%\data"
|
||||||
set CLASSPATH_FRAG=%GHIDRA_HOME%\%MODULE_DIR%\data\classpath.frag
|
set "CLASSPATH_FRAG=%GHIDRA_HOME%\%MODULE_DIR%\data\classpath.frag"
|
||||||
set LS_CPATH=%GHIDRA_HOME%\support\LaunchSupport.jar
|
set "LS_CPATH=%GHIDRA_HOME%\support\LaunchSupport.jar"
|
||||||
|
|
||||||
:lab1
|
:lab1
|
||||||
|
|
||||||
rem set WRAPPER_HOME to unpacked yajsw location (crazy FOR syntax to set variable from command output)
|
rem set WRAPPER_HOME to unpacked yajsw location (crazy FOR syntax to set variable from command output)
|
||||||
for /F "usebackq delims=" %%p in (`dir "%DATA_DIR%" /ad /b ^| findstr "^%WRAPPER_NAME_PREFIX%"`) do set WRAPPER_DIRNAME=%%p
|
for /F "usebackq delims=" %%p in (`dir "%DATA_DIR%" /ad /b ^| findstr "^%WRAPPER_NAME_PREFIX%"`) do set WRAPPER_DIRNAME=%%p
|
||||||
set WRAPPER_HOME=%DATA_DIR%\%WRAPPER_DIRNAME%
|
set "WRAPPER_HOME=%DATA_DIR%\%WRAPPER_DIRNAME%"
|
||||||
|
|
||||||
if not exist "%WRAPPER_HOME%\" (
|
if not exist "%WRAPPER_HOME%\" (
|
||||||
echo.
|
echo.
|
||||||
|
@ -104,8 +104,7 @@ set ERROR=ERROR: JAVA_HOME is not set and no 'java' command could be found in yo
|
||||||
goto reportError
|
goto reportError
|
||||||
|
|
||||||
:findJavaFromJavaHome
|
:findJavaFromJavaHome
|
||||||
set JAVA_HOME=%JAVA_HOME:"=%
|
set "JAVA=%JAVA_HOME%\bin\java.exe"
|
||||||
set JAVA=%JAVA_HOME%\bin\java.exe
|
|
||||||
|
|
||||||
if exist "%JAVA%" goto lab2
|
if exist "%JAVA%" goto lab2
|
||||||
set ERROR=ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
set ERROR=ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||||
|
@ -122,15 +121,7 @@ if "%JAVA_HOME%" == "" (
|
||||||
)
|
)
|
||||||
|
|
||||||
rem reestablish JAVA path based upon final JAVA_HOME
|
rem reestablish JAVA path based upon final JAVA_HOME
|
||||||
set JAVA=%JAVA_HOME%\bin\java.exe
|
set "JAVA=%JAVA_HOME%\bin\java.exe"
|
||||||
|
|
||||||
set OS_NAME=win32
|
|
||||||
"%JAVA%" -version 2>&1 | findstr /I " 64-Bit " >NUL
|
|
||||||
if errorlevel 0 (
|
|
||||||
set OS_NAME=win64
|
|
||||||
)
|
|
||||||
|
|
||||||
set OS_DIR=%GHIDRA_HOME%\%MODULE_DIR%\os\%OS_NAME%
|
|
||||||
|
|
||||||
:: set DEBUG=-Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=*:18888
|
:: set DEBUG=-Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=*:18888
|
||||||
|
|
||||||
|
|
|
@ -31,18 +31,18 @@ set MAXMEM=128M
|
||||||
:: '% ~' dereferences the value in param 0
|
:: '% ~' dereferences the value in param 0
|
||||||
:: 'd' - drive
|
:: 'd' - drive
|
||||||
:: 'p' - path (without filename)
|
:: 'p' - path (without filename)
|
||||||
set SCRIPT_DIR=%~dp0
|
set "SCRIPT_DIR=%~dp0"
|
||||||
|
|
||||||
:: Production Environment
|
:: Production Environment
|
||||||
set CONFIG=%SCRIPT_DIR%.\server.conf
|
set "CONFIG=%SCRIPT_DIR%.\server.conf"
|
||||||
|
|
||||||
if exist "%CONFIG%" goto continue
|
if exist "%CONFIG%" goto continue
|
||||||
|
|
||||||
:: Development Environment
|
:: Development Environment
|
||||||
set CONFIG=%SCRIPT_DIR%..\..\Common\server\server.conf
|
set "CONFIG=%SCRIPT_DIR%..\..\Common\server\server.conf"
|
||||||
|
|
||||||
:continue
|
:continue
|
||||||
|
|
||||||
set VMARGS=-DUserAdmin.invocation="%0" -DUserAdmin.config="%CONFIG%"
|
set VMARGS=-DUserAdmin.invocation=%~n0
|
||||||
|
|
||||||
call "%~dp0\..\support\launch.bat" fg svrAdmin "%MAXMEM%" "%VMARGS%" ghidra.server.ServerAdmin %*
|
call "%~dp0\..\support\launch.bat" fg svrAdmin "%MAXMEM%" "%VMARGS%" ghidra.server.ServerAdmin "%CONFIG%" %*
|
||||||
|
|
|
@ -3,7 +3,7 @@ setlocal
|
||||||
|
|
||||||
rem Find the script directory
|
rem Find the script directory
|
||||||
rem %~dsp0 is location of current script under NT
|
rem %~dsp0 is location of current script under NT
|
||||||
set _REALPATH=%~dp0
|
set "_REALPATH=%~dp0"
|
||||||
|
|
||||||
call "%_REALPATH%\ghidraSvr" install
|
call "%_REALPATH%\ghidraSvr" install
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ setlocal
|
||||||
|
|
||||||
rem Find the script directory
|
rem Find the script directory
|
||||||
rem %~dsp0 is location of current script under NT
|
rem %~dsp0 is location of current script under NT
|
||||||
set _REALPATH=%~dp0
|
set "_REALPATH=%~dp0"
|
||||||
|
|
||||||
call "%_REALPATH%\ghidraSvr" uninstall
|
call "%_REALPATH%\ghidraSvr" uninstall
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ set VMARG_LIST=-XX:ParallelGCThreads=2
|
||||||
set VMARG_LIST=%VMARG_LIST% -XX:CICompilerCount=2
|
set VMARG_LIST=%VMARG_LIST% -XX:CICompilerCount=2
|
||||||
|
|
||||||
:: store current path
|
:: store current path
|
||||||
set filepath=%~dp0
|
set "filepath=%~dp0"
|
||||||
|
|
||||||
:: Loop through parameters (if there aren't any, just continue) and store
|
:: Loop through parameters (if there aren't any, just continue) and store
|
||||||
:: in params variable.
|
:: in params variable.
|
||||||
|
|
|
@ -8,9 +8,9 @@ setlocal
|
||||||
set LAUNCH_MODE=fg
|
set LAUNCH_MODE=fg
|
||||||
|
|
||||||
:: Sets SCRIPT_DIR to the directory that contains this file (ends with '\')
|
:: Sets SCRIPT_DIR to the directory that contains this file (ends with '\')
|
||||||
set SCRIPT_DIR=%~dp0
|
set "SCRIPT_DIR=%~dp0"
|
||||||
|
|
||||||
set GHIDRA_ROOT_DIR=%SCRIPT_DIR%..\Ghidra
|
set "GHIDRA_ROOT_DIR=%SCRIPT_DIR%..\Ghidra"
|
||||||
if exist "%GHIDRA_ROOT_DIR%" goto continue
|
if exist "%GHIDRA_ROOT_DIR%" goto continue
|
||||||
|
|
||||||
echo This script does not support development mode use
|
echo This script does not support development mode use
|
||||||
|
@ -18,6 +18,6 @@ exit /B 1
|
||||||
|
|
||||||
:continue
|
:continue
|
||||||
|
|
||||||
set APP_VMARGS=-DGhidraJarBuilder.Name=%0 -DGhidra.Install.Root.Dir=%GHIDRA_ROOT_DIR%
|
set APP_VMARGS=-DGhidraJarBuilder.Name=%~n0
|
||||||
|
|
||||||
call "%~dp0launch.bat" %LAUNCH_MODE% Ghidra "" "%APP_VMARGS%" ghidra.util.GhidraJarBuilder -main ghidra.JarRun %*
|
call "%~dp0launch.bat" %LAUNCH_MODE% Ghidra "" "%APP_VMARGS%" ghidra.util.GhidraJarBuilder -main ghidra.JarRun %*
|
||||||
|
|
|
@ -11,16 +11,16 @@
|
||||||
setlocal
|
setlocal
|
||||||
|
|
||||||
REM Get parent of current folder
|
REM Get parent of current folder
|
||||||
set SCRIPT_DIR=%~dp0
|
set "SCRIPT_DIR=%~dp0"
|
||||||
|
|
||||||
set GHIDRA_DIR=%SCRIPT_DIR%..\Ghidra
|
set "GHIDRA_DIR=%SCRIPT_DIR%..\Ghidra"
|
||||||
set OS_DIR=os
|
set OS_DIR=os
|
||||||
|
|
||||||
REM Production Environment
|
REM Production Environment
|
||||||
if exist "%GHIDRA_DIR%" goto continue
|
if exist "%GHIDRA_DIR%" goto continue
|
||||||
|
|
||||||
REM Development Environment
|
REM Development Environment
|
||||||
set GHIDRA_DIR=%SCRIPT_DIR%..\..\..
|
set "GHIDRA_DIR=%SCRIPT_DIR%..\..\.."
|
||||||
set OS_DIR=build\os
|
set OS_DIR=build\os
|
||||||
|
|
||||||
:continue
|
:continue
|
||||||
|
@ -35,7 +35,7 @@ if exist "%PROGRAMFILES(X86)%" (
|
||||||
set OS_TYPE=win32
|
set OS_TYPE=win32
|
||||||
)
|
)
|
||||||
|
|
||||||
set PDB_EXE=%GHIDRA_DIR%\Features\PDB\%OS_DIR%\%OS_TYPE%\pdb.exe
|
set "PDB_EXE=%GHIDRA_DIR%\Features\PDB\%OS_DIR%\%OS_TYPE%\pdb.exe"
|
||||||
|
|
||||||
if not exist "%PDB_EXE%" (
|
if not exist "%PDB_EXE%" (
|
||||||
echo "%PDB_EXE% not found"
|
echo "%PDB_EXE% not found"
|
||||||
|
|
|
@ -36,7 +36,7 @@ for /f "tokens=2" %%# in ("%cmdcmdline%") do if /i "%%#" equ "/c" set DOUBLE_CLI
|
||||||
:: '% ~' dereferences the value in param 0
|
:: '% ~' dereferences the value in param 0
|
||||||
:: 'd' - drive
|
:: 'd' - drive
|
||||||
:: 'p' - path (without filename)
|
:: 'p' - path (without filename)
|
||||||
set SUPPORT_DIR=%~dp0
|
set "SUPPORT_DIR=%~dp0"
|
||||||
|
|
||||||
::
|
::
|
||||||
:: Parse arguments
|
:: Parse arguments
|
||||||
|
@ -63,20 +63,20 @@ goto showUsage
|
||||||
::
|
::
|
||||||
:: Production Environment
|
:: Production Environment
|
||||||
::
|
::
|
||||||
set INSTALL_DIR=%SUPPORT_DIR%..\
|
set "INSTALL_DIR=%SUPPORT_DIR%..\"
|
||||||
set CPATH=%INSTALL_DIR%Ghidra\Framework\Utility\lib\Utility.jar
|
set "CPATH=%INSTALL_DIR%Ghidra\Framework\Utility\lib\Utility.jar"
|
||||||
set LS_CPATH=%SUPPORT_DIR%LaunchSupport.jar
|
set "LS_CPATH=%SUPPORT_DIR%LaunchSupport.jar"
|
||||||
set DEBUG_LOG4J=%SUPPORT_DIR%debug.log4j.xml
|
set "DEBUG_LOG4J=%SUPPORT_DIR%debug.log4j.xml"
|
||||||
|
|
||||||
if exist "%INSTALL_DIR%Ghidra" goto continue2
|
if exist "%INSTALL_DIR%Ghidra" goto continue2
|
||||||
|
|
||||||
::
|
::
|
||||||
:: Development Environment
|
:: Development Environment
|
||||||
::
|
::
|
||||||
set INSTALL_DIR=%INSTALL_DIR%..\..\..\
|
set "INSTALL_DIR=%INSTALL_DIR%..\..\..\"
|
||||||
set CPATH=%INSTALL_DIR%Ghidra\Framework\Utility\bin\main
|
set "CPATH=%INSTALL_DIR%Ghidra\Framework\Utility\bin\main"
|
||||||
set LS_CPATH=%INSTALL_DIR%GhidraBuild\LaunchSupport\bin\main
|
set "LS_CPATH=%INSTALL_DIR%GhidraBuild\LaunchSupport\bin\main"
|
||||||
set DEBUG_LOG4J=%INSTALL_DIR%Ghidra\RuntimeScripts\Common\support\debug.log4j.xml
|
set "DEBUG_LOG4J=%INSTALL_DIR%Ghidra\RuntimeScripts\Common\support\debug.log4j.xml"
|
||||||
|
|
||||||
:continue2
|
:continue2
|
||||||
|
|
||||||
|
@ -108,7 +108,7 @@ if "%JAVA_HOME%" == "" (
|
||||||
goto exit1
|
goto exit1
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
set JAVA_CMD=%JAVA_HOME%\bin\java
|
set "JAVA_CMD=%JAVA_HOME%\bin\java"
|
||||||
|
|
||||||
:: Get the configurable VM arguments from the launch properties
|
:: Get the configurable VM arguments from the launch properties
|
||||||
for /f "delims=*" %%i in ('java -cp "%LS_CPATH%" LaunchSupport "%INSTALL_DIR%\" -vmargs') do set VMARG_LIST=%VMARG_LIST% %%i
|
for /f "delims=*" %%i in ('java -cp "%LS_CPATH%" LaunchSupport "%INSTALL_DIR%\" -vmargs') do set VMARG_LIST=%VMARG_LIST% %%i
|
||||||
|
|
|
@ -26,6 +26,6 @@ set VMARG_LIST=-XX:ParallelGCThreads=2
|
||||||
set VMARG_LIST=%VMARG_LIST% -XX:CICompilerCount=2
|
set VMARG_LIST=%VMARG_LIST% -XX:CICompilerCount=2
|
||||||
|
|
||||||
:: store current path
|
:: store current path
|
||||||
set filepath=%~dp0
|
set "filepath=%~dp0"
|
||||||
|
|
||||||
call "%filepath%launch.bat" %LAUNCH_MODE% Ghidra-Python "%MAXMEM%" "%VMARG_LIST%" ghidra.python.PythonRun %params%
|
call "%filepath%launch.bat" %LAUNCH_MODE% Ghidra-Python "%MAXMEM%" "%VMARG_LIST%" ghidra.python.PythonRun %params%
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue