mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-06-02 13:37:56 +08:00
changes from review
This commit is contained in:
@@ -1,221 +0,0 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.server.remote;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import ghidra.util.Msg;
|
||||
|
||||
/**
|
||||
* <code>RMIClassServer</code> provides a server for serializing classes to an
|
||||
* RMI client as needed. This implementation starts a new listener thread each
|
||||
* time a connection is accepted.
|
||||
*/
|
||||
public class RMIClassServer implements Runnable {
|
||||
|
||||
private static RMIClassServer classServer;
|
||||
|
||||
private ServerSocket server;
|
||||
|
||||
private ArrayList<Thread> threads = new ArrayList<Thread>();
|
||||
|
||||
/**
|
||||
* Construct a new server.
|
||||
* @param port
|
||||
* @throws IOException if port is in use or not permitted.
|
||||
*/
|
||||
private RMIClassServer(int port) throws IOException {
|
||||
if (classServer != null) {
|
||||
throw new RuntimeException("Class server already running");
|
||||
}
|
||||
classServer = this;
|
||||
server = new ServerSocket(port);
|
||||
newListener();
|
||||
}
|
||||
|
||||
private void dispose() {
|
||||
synchronized (RMIClassServer.class) {
|
||||
classServer = null;
|
||||
for (Thread t : threads) {
|
||||
t.interrupt();
|
||||
}
|
||||
if (server != null) {
|
||||
try {
|
||||
server.close();
|
||||
} catch (IOException e) {
|
||||
}
|
||||
server = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void newListener() {
|
||||
synchronized (RMIClassServer.class) {
|
||||
if (classServer == this) { // make sure we have not been stopped
|
||||
Thread t = new Thread(this, "RMI Class Server");
|
||||
threads.add(t);
|
||||
t.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @see java.lang.Runnable#run()
|
||||
*/
|
||||
public void run() {
|
||||
|
||||
// accept connection
|
||||
Socket socket = null;
|
||||
try {
|
||||
socket = server.accept();
|
||||
} catch (NullPointerException e) {
|
||||
// Just in case server is null after dispose
|
||||
} catch (InterruptedIOException e) {
|
||||
} catch (Throwable t) {
|
||||
Msg.error(this, "Class server error: " + t.toString(), t);
|
||||
}
|
||||
|
||||
synchronized (RMIClassServer.class) {
|
||||
|
||||
// create a new thread to accept the next connection
|
||||
newListener();
|
||||
|
||||
if (socket == null) {
|
||||
threads.remove(Thread.currentThread());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
DataOutputStream out = new DataOutputStream(socket.getOutputStream());
|
||||
try {
|
||||
// get path to class file
|
||||
DataInputStream in = new DataInputStream(socket.getInputStream());
|
||||
String path = getClassName(in);
|
||||
|
||||
byte[] bytecodes = getBytes(path);
|
||||
|
||||
// send bytecodes in response (assumes HTTP/1.0 or later)
|
||||
try {
|
||||
out.writeBytes("HTTP/1.0 200 OK\r\n");
|
||||
out.writeBytes("Content-Length: " + bytecodes.length + "\r\n");
|
||||
out.writeBytes("Content-Type: application/java\r\n\r\n");
|
||||
out.write(bytecodes);
|
||||
out.flush();
|
||||
} catch (IOException ie) {
|
||||
return;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// write out error response
|
||||
out.writeBytes("HTTP/1.0 400 " + e.getMessage() + "\r\n");
|
||||
out.writeBytes("Content-Type: text/html\r\n\r\n");
|
||||
out.flush();
|
||||
}
|
||||
} catch (InterruptedIOException e) {
|
||||
} catch (Throwable t) {
|
||||
// eat exception
|
||||
Msg.error(this, "error writing response: " + t.getMessage(), t);
|
||||
}
|
||||
|
||||
try {
|
||||
socket.close();
|
||||
} catch (IOException e) {
|
||||
} finally {
|
||||
synchronized (RMIClassServer.class) {
|
||||
threads.remove(Thread.currentThread());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the full classname requested or null if not a valid class file request.
|
||||
* Consumes all input from client.
|
||||
* @param in HTTP input stream
|
||||
* @return class name including package prefix
|
||||
* @throws IOException if request was not for a class file
|
||||
*/
|
||||
private String getClassName(DataInputStream in) throws IOException {
|
||||
String line = in.readLine();
|
||||
String path = "";
|
||||
|
||||
if (line.startsWith("GET /")) {
|
||||
line = line.substring(5, line.length()-1).trim();
|
||||
int index = line.indexOf(".class");
|
||||
if (index != -1) {
|
||||
path = line.substring(0, index+6);
|
||||
}
|
||||
}
|
||||
|
||||
// eat the rest of header
|
||||
do {
|
||||
line = in.readLine();
|
||||
} while ((line.length() != 0));
|
||||
|
||||
if (path.length() != 0) {
|
||||
return path;
|
||||
}
|
||||
throw new IOException("Malformed Header");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get byte code data for specified classname
|
||||
* @param classname full class name including package
|
||||
* @return byte-code data for class
|
||||
*/
|
||||
private byte[] getBytes(String classname) throws IOException {
|
||||
|
||||
InputStream istream = ClassLoader.getSystemResourceAsStream(classname);
|
||||
if (istream == null) {
|
||||
throw new IOException("Class not found");
|
||||
}
|
||||
|
||||
try {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
DataInputStream in = new DataInputStream(istream);
|
||||
byte[] buf = new byte[4096];
|
||||
int readLen = 0;
|
||||
while ((readLen = in.read(buf)) >= 0) {
|
||||
out.write(buf, 0, readLen);
|
||||
}
|
||||
return out.toByteArray();
|
||||
}
|
||||
finally {
|
||||
istream.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a class file server.
|
||||
* @param port port to use
|
||||
*/
|
||||
static synchronized void startServer(int port) throws IOException {
|
||||
new RMIClassServer(port);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop the class server if running
|
||||
*/
|
||||
static synchronized void stopServer() {
|
||||
if (classServer != null) {
|
||||
Msg.info(RMIClassServer.class, "Stopping class server...");
|
||||
classServer.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-4
@@ -310,12 +310,11 @@ class CheckoutManager {
|
||||
Element root = new Element("CHECKOUT_LIST");
|
||||
root.setAttribute("NEXT_ID", Long.toString(nextCheckoutId));
|
||||
|
||||
for (long id : checkouts.keySet()) {
|
||||
ItemCheckoutStatus coStatus = checkouts.get(id);
|
||||
for (ItemCheckoutStatus status : checkouts.values()) {
|
||||
// TRANSIENT checkout data must not be persisted - the existence
|
||||
// of such checkouts is retained in-memory only
|
||||
if (coStatus.getCheckoutType() != CheckoutType.TRANSIENT) {
|
||||
root.addContent(getCheckoutElement(coStatus));
|
||||
if (status.getCheckoutType() != CheckoutType.TRANSIENT) {
|
||||
root.addContent(getCheckoutElement(status));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -105,37 +105,6 @@ public class ObjectCache {
|
||||
addToHardCache(obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear both hard and weak caches.
|
||||
* The cache should be cleared when all cached objects have become invalid.
|
||||
*/
|
||||
public synchronized void clear() {
|
||||
processQueue();
|
||||
for (KeyedSoftReference<?> ref : hashTable.values()) {
|
||||
ref.clear();
|
||||
}
|
||||
|
||||
hashTable.clear();
|
||||
refQueue = new ReferenceQueue<Object>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified range of keyed objects from both hard and weak caches.
|
||||
* A cache range should be cleared when the corresponding objects have become invalid.
|
||||
* @param startKey minimum object key value
|
||||
* @param endKey maximum object key value
|
||||
*/
|
||||
public synchronized void remove(long startKey, long endKey) {
|
||||
if ((endKey >> 1) - (startKey >> 1) < (hashTable.size() >> 1)) {
|
||||
for (long i = startKey; i <= endKey; i++) {
|
||||
remove(i);
|
||||
}
|
||||
}
|
||||
else {
|
||||
hashTable.keySet().removeIf(key -> (key >= startKey && key <= endKey));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified keyed object from both hard and weak caches.
|
||||
* An object should be removed from the cache when it becomes invalid.
|
||||
|
||||
+1
-1
@@ -35,7 +35,7 @@ public class StringAttribute<T extends KeyedObject> extends Attribute<T> {
|
||||
*/
|
||||
public StringAttribute(String name, KeyIndexableSet<T> set) {
|
||||
super(name, set);
|
||||
this.values = new HashMap<>(set.capacity());// String[set.capacity()];
|
||||
this.values = new HashMap<>();
|
||||
}
|
||||
|
||||
/** Set the value of this attribute for the specified KeyedObject.
|
||||
|
||||
+2
-5
@@ -162,11 +162,8 @@ class OverlaySpaceAdapterDB {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (map.size() != 0) {
|
||||
for (OverlayAddressSpace space : map.values()) {
|
||||
factory.removeOverlaySpace(space.getName());
|
||||
}
|
||||
map.clear();
|
||||
for (OverlayAddressSpace space : map.values()) {
|
||||
factory.removeOverlaySpace(space.getName());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+35
-15
@@ -1,6 +1,5 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,6 +15,11 @@
|
||||
*/
|
||||
package ghidra.program.database.properties;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
import db.*;
|
||||
import db.util.ErrorHandler;
|
||||
import ghidra.program.database.map.*;
|
||||
import ghidra.program.database.util.DatabaseTableUtils;
|
||||
import ghidra.program.model.address.*;
|
||||
@@ -28,12 +32,6 @@ import ghidra.util.exception.*;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
import ghidra.util.task.TaskMonitorAdapter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
import db.*;
|
||||
import db.util.ErrorHandler;
|
||||
|
||||
/**
|
||||
* Abstract class which defines a map containing properties over a set of addresses.
|
||||
* The map is stored within a database table.
|
||||
@@ -137,8 +135,9 @@ public abstract class PropertyMapDB implements PropertyMap {
|
||||
monitor.setProgress(++count);
|
||||
}
|
||||
|
||||
if (tempTable == null)
|
||||
if (tempTable == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove old table
|
||||
dbHandle.deleteTable(getTableName());
|
||||
@@ -192,6 +191,7 @@ public abstract class PropertyMapDB implements PropertyMap {
|
||||
/**
|
||||
* @see ghidra.program.model.util.PropertyMap#getName()
|
||||
*/
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
@@ -221,7 +221,7 @@ public abstract class PropertyMapDB implements PropertyMap {
|
||||
lock.acquire();
|
||||
try {
|
||||
if (propertyTable != null) {
|
||||
cache.clear();
|
||||
cache = null;
|
||||
dbHandle.deleteTable(getTableName());
|
||||
propertyTable = null;
|
||||
}
|
||||
@@ -234,6 +234,7 @@ public abstract class PropertyMapDB implements PropertyMap {
|
||||
/**
|
||||
* @see ghidra.program.model.util.PropertyMap#intersects(ghidra.program.model.address.Address, ghidra.program.model.address.Address)
|
||||
*/
|
||||
@Override
|
||||
public boolean intersects(Address startAddr, Address endAddr) {
|
||||
if (propertyTable == null) {
|
||||
return false;
|
||||
@@ -252,6 +253,7 @@ public abstract class PropertyMapDB implements PropertyMap {
|
||||
/**
|
||||
* @see ghidra.program.model.util.PropertyMap#intersects(ghidra.program.model.address.AddressSetView)
|
||||
*/
|
||||
@Override
|
||||
public boolean intersects(AddressSetView set) {
|
||||
if (propertyTable == null) {
|
||||
return false;
|
||||
@@ -270,6 +272,7 @@ public abstract class PropertyMapDB implements PropertyMap {
|
||||
/**
|
||||
* @see ghidra.program.model.util.PropertyMap#removeRange(ghidra.program.model.address.Address, ghidra.program.model.address.Address)
|
||||
*/
|
||||
@Override
|
||||
public boolean removeRange(Address startAddr, Address endAddr) {
|
||||
if (propertyTable == null) {
|
||||
return false;
|
||||
@@ -277,7 +280,7 @@ public abstract class PropertyMapDB implements PropertyMap {
|
||||
lock.acquire();
|
||||
try {
|
||||
if (AddressRecordDeleter.deleteRecords(propertyTable, addrMap, startAddr, endAddr)) {
|
||||
cache.clear();
|
||||
cache = new ObjectCache(DEFAULT_CACHE_SIZE);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -293,6 +296,7 @@ public abstract class PropertyMapDB implements PropertyMap {
|
||||
/**
|
||||
* @see ghidra.program.model.util.PropertyMap#remove(ghidra.program.model.address.Address)
|
||||
*/
|
||||
@Override
|
||||
public boolean remove(Address addr) {
|
||||
if (propertyTable == null) {
|
||||
return false;
|
||||
@@ -317,6 +321,7 @@ public abstract class PropertyMapDB implements PropertyMap {
|
||||
/**
|
||||
* @see ghidra.program.model.util.PropertyMap#hasProperty(ghidra.program.model.address.Address)
|
||||
*/
|
||||
@Override
|
||||
public boolean hasProperty(Address addr) {
|
||||
if (propertyTable == null) {
|
||||
return false;
|
||||
@@ -341,6 +346,7 @@ public abstract class PropertyMapDB implements PropertyMap {
|
||||
/**
|
||||
* @see ghidra.program.model.util.PropertyMap#getNextPropertyAddress(ghidra.program.model.address.Address)
|
||||
*/
|
||||
@Override
|
||||
public Address getNextPropertyAddress(Address addr) {
|
||||
if (propertyTable == null) {
|
||||
return null;
|
||||
@@ -360,6 +366,7 @@ public abstract class PropertyMapDB implements PropertyMap {
|
||||
/**
|
||||
* @see ghidra.program.model.util.PropertyMap#getPreviousPropertyAddress(ghidra.program.model.address.Address)
|
||||
*/
|
||||
@Override
|
||||
public Address getPreviousPropertyAddress(Address addr) {
|
||||
if (propertyTable == null) {
|
||||
return null;
|
||||
@@ -379,6 +386,7 @@ public abstract class PropertyMapDB implements PropertyMap {
|
||||
/**
|
||||
* @see ghidra.program.model.util.PropertyMap#getFirstPropertyAddress()
|
||||
*/
|
||||
@Override
|
||||
public Address getFirstPropertyAddress() {
|
||||
if (propertyTable == null) {
|
||||
return null;
|
||||
@@ -398,6 +406,7 @@ public abstract class PropertyMapDB implements PropertyMap {
|
||||
/**
|
||||
* @see ghidra.program.model.util.PropertyMap#getLastPropertyAddress()
|
||||
*/
|
||||
@Override
|
||||
public Address getLastPropertyAddress() {
|
||||
if (propertyTable == null) {
|
||||
return null;
|
||||
@@ -419,6 +428,7 @@ public abstract class PropertyMapDB implements PropertyMap {
|
||||
/**
|
||||
* @see ghidra.program.model.util.PropertyMap#getSize()
|
||||
*/
|
||||
@Override
|
||||
public int getSize() {
|
||||
return propertyTable != null ? propertyTable.getRecordCount() : 0;
|
||||
}
|
||||
@@ -434,8 +444,9 @@ public abstract class PropertyMapDB implements PropertyMap {
|
||||
public AddressKeyIterator getAddressKeyIterator(AddressSetView set, boolean atStart)
|
||||
throws IOException {
|
||||
|
||||
if (propertyTable == null)
|
||||
if (propertyTable == null) {
|
||||
return new AddressKeyIterator();
|
||||
}
|
||||
if (atStart) {
|
||||
return new AddressKeyIterator(propertyTable, addrMap, set, set.getMinAddress(), true);
|
||||
}
|
||||
@@ -452,8 +463,9 @@ public abstract class PropertyMapDB implements PropertyMap {
|
||||
public AddressKeyIterator getAddressKeyIterator(Address start, boolean before)
|
||||
throws IOException {
|
||||
|
||||
if (propertyTable == null)
|
||||
if (propertyTable == null) {
|
||||
return new AddressKeyIterator();
|
||||
}
|
||||
return new AddressKeyIterator(propertyTable, addrMap, start, before);
|
||||
}
|
||||
|
||||
@@ -469,8 +481,9 @@ public abstract class PropertyMapDB implements PropertyMap {
|
||||
public AddressKeyIterator getAddressKeyIterator(Address start, Address end, boolean atStart)
|
||||
throws IOException {
|
||||
|
||||
if (propertyTable == null)
|
||||
if (propertyTable == null) {
|
||||
return new AddressKeyIterator();
|
||||
}
|
||||
if (atStart) {
|
||||
return new AddressKeyIterator(propertyTable, addrMap, start, end, start, true);
|
||||
}
|
||||
@@ -480,6 +493,7 @@ public abstract class PropertyMapDB implements PropertyMap {
|
||||
/**
|
||||
* @see ghidra.program.model.util.PropertyMap#getPropertyIterator(ghidra.program.model.address.Address, ghidra.program.model.address.Address)
|
||||
*/
|
||||
@Override
|
||||
public AddressIterator getPropertyIterator(Address start, Address end) {
|
||||
AddressKeyIterator keyIter = null;
|
||||
try {
|
||||
@@ -494,6 +508,7 @@ public abstract class PropertyMapDB implements PropertyMap {
|
||||
/**
|
||||
* @see ghidra.program.model.util.PropertyMap#getPropertyIterator(ghidra.program.model.address.Address, ghidra.program.model.address.Address, boolean)
|
||||
*/
|
||||
@Override
|
||||
public AddressIterator getPropertyIterator(Address start, Address end, boolean forward) {
|
||||
AddressKeyIterator keyIter = null;
|
||||
try {
|
||||
@@ -508,6 +523,7 @@ public abstract class PropertyMapDB implements PropertyMap {
|
||||
/**
|
||||
* @see ghidra.program.model.util.PropertyMap#getPropertyIterator()
|
||||
*/
|
||||
@Override
|
||||
public AddressIterator getPropertyIterator() {
|
||||
if (propertyTable == null) {
|
||||
return new EmptyAddressIterator();
|
||||
@@ -525,6 +541,7 @@ public abstract class PropertyMapDB implements PropertyMap {
|
||||
/**
|
||||
* @see ghidra.program.model.util.PropertyMap#getPropertyIterator(ghidra.program.model.address.AddressSetView)
|
||||
*/
|
||||
@Override
|
||||
public AddressIterator getPropertyIterator(AddressSetView asv) {
|
||||
if (propertyTable == null) {
|
||||
return new EmptyAddressIterator();
|
||||
@@ -543,6 +560,7 @@ public abstract class PropertyMapDB implements PropertyMap {
|
||||
/**
|
||||
* @see ghidra.program.model.util.PropertyMap#getPropertyIterator(ghidra.program.model.address.AddressSetView, boolean)
|
||||
*/
|
||||
@Override
|
||||
public AddressIterator getPropertyIterator(AddressSetView asv, boolean forward) {
|
||||
if (propertyTable == null) {
|
||||
return new EmptyAddressIterator();
|
||||
@@ -567,6 +585,7 @@ public abstract class PropertyMapDB implements PropertyMap {
|
||||
/**
|
||||
* @see ghidra.program.model.util.PropertyMap#getPropertyIterator(ghidra.program.model.address.Address, boolean)
|
||||
*/
|
||||
@Override
|
||||
public AddressIterator getPropertyIterator(Address start, boolean forward) {
|
||||
if (propertyTable == null) {
|
||||
return new EmptyAddressIterator();
|
||||
@@ -588,7 +607,7 @@ public abstract class PropertyMapDB implements PropertyMap {
|
||||
lock.acquire();
|
||||
try {
|
||||
propertyTable = dbHandle.getTable(getTableName());
|
||||
cache.clear();
|
||||
cache = new ObjectCache(DEFAULT_CACHE_SIZE);
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
@@ -599,10 +618,11 @@ public abstract class PropertyMapDB implements PropertyMap {
|
||||
/**
|
||||
* @see ghidra.program.model.util.PropertyMap#moveRange(ghidra.program.model.address.Address, ghidra.program.model.address.Address, ghidra.program.model.address.Address)
|
||||
*/
|
||||
@Override
|
||||
public void moveRange(Address start, Address end, Address newStart) {
|
||||
lock.acquire();
|
||||
try {
|
||||
cache.clear();
|
||||
cache = new ObjectCache(DEFAULT_CACHE_SIZE);
|
||||
if (propertyTable != null) {
|
||||
try {
|
||||
DatabaseTableUtils.updateAddressKey(propertyTable, addrMap, start, end,
|
||||
|
||||
Reference in New Issue
Block a user