GP-706 - Speed up namespace lookup and creation

This commit is contained in:
dragonmacher 2021-03-18 12:13:28 -04:00
parent 79fce9b032
commit ae69ba87d1
35 changed files with 862 additions and 633 deletions

View file

@ -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;
}
} }

View file

@ -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);
} }

View file

@ -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;
} }

View file

@ -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]);
}
} }

View file

@ -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;
}
} }

View file

@ -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;

View file

@ -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>

View file

@ -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>

View file

@ -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);

View file

@ -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);
} }
} }

View file

@ -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);
} }

View file

@ -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(

View file

@ -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

View file

@ -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")));
}
} }

View file

@ -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();

View file

@ -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;
} }

View file

@ -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) {

View file

@ -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;
} }
} }

View file

@ -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));
} }

View file

@ -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()
*/ */

View file

@ -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;
} }

View file

@ -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;
} }
} }

View file

@ -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;
} }

View file

@ -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

View file

@ -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" "$@"

View file

@ -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 "$@"

View file

@ -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

View file

@ -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%" %*

View file

@ -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

View file

@ -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

View file

@ -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.

View file

@ -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 %*

View file

@ -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"

View file

@ -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

View file

@ -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%