mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-06-01 14:28:22 +08:00
Merge remote-tracking branch 'origin/GP-6097_ghidragon_read_write_lock--SQUASHED'
This commit is contained in:
-9
@@ -43,7 +43,6 @@ public class BookmarkNavigator {
|
||||
final static Icon WARNING_ICON = new GIcon("icon.plugin.bookmark.type.warning");
|
||||
final static Icon ERROR_ICON = new GIcon("icon.plugin.bookmark.type.error");
|
||||
final static Icon ANALYSIS_ICON = new GIcon("icon.plugin.bookmark.type.analysis");
|
||||
final static Icon DEFAULT_ICON = new GIcon("icon.plugin.bookmark.type.default");
|
||||
|
||||
final static int NOTE_PRIORITY = MarkerService.BOOKMARK_PRIORITY;
|
||||
final static int ERROR_PRIORITY = MarkerService.BOOKMARK_PRIORITY + BIG_CHANGE;
|
||||
@@ -81,14 +80,6 @@ public class BookmarkNavigator {
|
||||
}
|
||||
|
||||
Icon icon = bmt.getIcon();
|
||||
if (icon == null) {
|
||||
if (bookmarkManager.isDefinedType(type)) {
|
||||
// This implies the client defined a type, but did not pass a valid icon. In this
|
||||
// case we will show a special icon.
|
||||
icon = DEFAULT_ICON;
|
||||
}
|
||||
}
|
||||
|
||||
Color color = bmt.getMarkerColor();
|
||||
if (color == null) {
|
||||
color = DEFAULT_COLOR;
|
||||
|
||||
+3
-3
@@ -21,7 +21,7 @@ import javax.help.UnsupportedOperationException;
|
||||
|
||||
import docking.widgets.OptionDialog;
|
||||
import docking.widgets.fieldpanel.support.*;
|
||||
import ghidra.program.database.DatabaseObject;
|
||||
import ghidra.program.database.DbObject;
|
||||
import ghidra.program.database.data.DataTypeUtilities;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.lang.InsufficientBytesException;
|
||||
@@ -1443,7 +1443,7 @@ public abstract class CompEditorModel<T extends Composite> extends CompositeEdit
|
||||
else {
|
||||
// Check for managed datatype changing
|
||||
DataType originalDt = originalDTM.getDataType(newPath);
|
||||
if (!(originalDt instanceof DatabaseObject)) {
|
||||
if (!(originalDt instanceof DbObject)) {
|
||||
return;
|
||||
}
|
||||
DataType dt = viewDTM.findMyDataTypeFromOriginalID(originalDTM.getID(originalDt));
|
||||
@@ -1532,7 +1532,7 @@ public abstract class CompEditorModel<T extends Composite> extends CompositeEdit
|
||||
// undo transactions for the viewDTM. An editor save could generate quite a few with
|
||||
// potentially many types getting changed by one change.
|
||||
DataType changedDt = originalDTM.getDataType(path);
|
||||
if (!(changedDt instanceof DatabaseObject)) {
|
||||
if (!(changedDt instanceof DbObject)) {
|
||||
return;
|
||||
}
|
||||
DataType viewDt =
|
||||
|
||||
+8
-8
@@ -22,7 +22,7 @@ import java.util.TreeSet;
|
||||
import javax.help.UnsupportedOperationException;
|
||||
|
||||
import db.util.ErrorHandler;
|
||||
import ghidra.program.database.DatabaseObject;
|
||||
import ghidra.program.database.DbObject;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.lang.ProgramArchitecture;
|
||||
import ghidra.util.Swing;
|
||||
@@ -231,7 +231,7 @@ public class CompositeViewerDataTypeManager<T extends Composite> extends StandAl
|
||||
return viewComposite;
|
||||
}
|
||||
DataType resolvedDt = super.resolve(dataType, handler);
|
||||
if ((dataType instanceof DatabaseObject) && originalDTM.contains(dataType)) {
|
||||
if ((dataType instanceof DbObject) && originalDTM.contains(dataType)) {
|
||||
long originalId = originalDTM.getID(dataType);
|
||||
long myId = getID(resolvedDt);
|
||||
dataTypeIDMap.put(myId, originalId);
|
||||
@@ -247,14 +247,14 @@ public class CompositeViewerDataTypeManager<T extends Composite> extends StandAl
|
||||
throw new IllegalArgumentException("datatype is not from this manager");
|
||||
}
|
||||
|
||||
if (existingViewDt instanceof DatabaseObject) {
|
||||
if (existingViewDt instanceof DbObject) {
|
||||
dataTypeIDMap.remove(getID(existingViewDt));
|
||||
}
|
||||
|
||||
DataType newResolvedDt =
|
||||
super.replaceDataType(existingViewDt, replacementDt, updateCategoryPath);
|
||||
|
||||
if (newResolvedDt instanceof DatabaseObject &&
|
||||
if (newResolvedDt instanceof DbObject &&
|
||||
replacementDt.getDataTypeManager() == originalDTM) {
|
||||
long originalId = originalDTM.getID(replacementDt);
|
||||
long myId = getID(newResolvedDt);
|
||||
@@ -271,7 +271,7 @@ public class CompositeViewerDataTypeManager<T extends Composite> extends StandAl
|
||||
throw new IllegalArgumentException("datatype is not from this manager");
|
||||
}
|
||||
|
||||
if (existingViewDt instanceof DatabaseObject) {
|
||||
if (existingViewDt instanceof DbObject) {
|
||||
dataTypeIDMap.remove(getID(existingViewDt));
|
||||
}
|
||||
|
||||
@@ -293,7 +293,7 @@ public class CompositeViewerDataTypeManager<T extends Composite> extends StandAl
|
||||
Iterator<DataType> allDataTypes = getAllDataTypes();
|
||||
while (allDataTypes.hasNext()) {
|
||||
DataType dt = allDataTypes.next();
|
||||
if (dt == viewComposite || !(dt instanceof DatabaseObject)) {
|
||||
if (dt == viewComposite || !(dt instanceof DbObject)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -396,7 +396,7 @@ public class CompositeViewerDataTypeManager<T extends Composite> extends StandAl
|
||||
long id = orphanIds.removeFirst();
|
||||
if (!hasParent(id)) {
|
||||
DataType dt = getDataType(id);
|
||||
if (dt instanceof DatabaseObject) {
|
||||
if (dt instanceof DbObject) {
|
||||
|
||||
if (dt == viewComposite) {
|
||||
continue;
|
||||
@@ -485,7 +485,7 @@ public class CompositeViewerDataTypeManager<T extends Composite> extends StandAl
|
||||
if (existingViewDt.getDataTypeManager() != this) {
|
||||
throw new IllegalArgumentException("datatype is not from this manager");
|
||||
}
|
||||
if (!(existingViewDt instanceof DatabaseObject)) {
|
||||
if (!(existingViewDt instanceof DbObject)) {
|
||||
return false;
|
||||
}
|
||||
return dataTypeIDMap.getOriginalIDFromViewID(getID(existingViewDt)) != null;
|
||||
|
||||
+4
-4
@@ -36,7 +36,7 @@ import ghidra.app.plugin.core.stackeditor.StackFrameDataType.StackComponentWrapp
|
||||
import ghidra.app.util.datatype.EmptyCompositeException;
|
||||
import ghidra.framework.plugintool.Plugin;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.database.DatabaseObject;
|
||||
import ghidra.program.database.DbObject;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.symbol.SourceType;
|
||||
@@ -1125,7 +1125,7 @@ public class StackEditorModel extends CompositeEditorModel<StackFrameDataType> {
|
||||
|
||||
// Check for managed datatype changing
|
||||
DataType originalDt = originalDTM.getDataType(newPath);
|
||||
if (!(originalDt instanceof DatabaseObject)) {
|
||||
if (!(originalDt instanceof DbObject)) {
|
||||
return;
|
||||
}
|
||||
DataType dt = viewDTM.findMyDataTypeFromOriginalID(originalDTM.getID(originalDt));
|
||||
@@ -1161,7 +1161,7 @@ public class StackEditorModel extends CompositeEditorModel<StackFrameDataType> {
|
||||
}
|
||||
|
||||
DataType changedDt = originalDTM.getDataType(path);
|
||||
if (!(changedDt instanceof DatabaseObject)) {
|
||||
if (!(changedDt instanceof DbObject)) {
|
||||
return;
|
||||
}
|
||||
DataType viewDt = viewDTM.findMyDataTypeFromOriginalID(originalDTM.getID(changedDt));
|
||||
@@ -1250,7 +1250,7 @@ public class StackEditorModel extends CompositeEditorModel<StackFrameDataType> {
|
||||
for (int i = comps.length - 1; i >= 0; i--) {
|
||||
DataTypeComponent component = comps[i];
|
||||
DataType compDt = component.getDataType();
|
||||
if (compDt instanceof DatabaseObject) {
|
||||
if (compDt instanceof DbObject) {
|
||||
// NOTE: viewDTM only maps view-to-original IDs for DataTypeDB
|
||||
long myId = viewDTM.getID(compDt);
|
||||
if (viewDTM.findOriginalDataTypeFromMyID(myId) == null) {
|
||||
|
||||
+2
-2
@@ -28,7 +28,7 @@ import ghidra.app.util.DataTypeNamingUtil;
|
||||
import ghidra.app.util.bin.format.dwarf.attribs.DWARFNumericAttribute;
|
||||
import ghidra.app.util.bin.format.dwarf.expression.DWARFExpressionException;
|
||||
import ghidra.app.util.bin.format.golang.rtti.types.GoKind;
|
||||
import ghidra.program.database.DatabaseObject;
|
||||
import ghidra.program.database.DbObject;
|
||||
import ghidra.program.database.data.DataTypeUtilities;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.data.Enum;
|
||||
@@ -247,7 +247,7 @@ public class DWARFDataTypeImporter {
|
||||
* offset -> ddt
|
||||
*/
|
||||
private void recordTempDataType(DWARFDataType ddt) {
|
||||
if (ddt.dataType instanceof DatabaseObject) {
|
||||
if (ddt.dataType instanceof DbObject) {
|
||||
// don't store info about types that are already in the database
|
||||
return;
|
||||
}
|
||||
|
||||
-1
@@ -455,7 +455,6 @@ abstract class OperandFieldHelper extends FieldFactory {
|
||||
if (separator != null) {
|
||||
results.add(separator);
|
||||
}
|
||||
|
||||
for (int opIndex = 0; opIndex < numOperands; opIndex++) {
|
||||
OpInfo opInfo = new OpInfo(inst, opIndex);
|
||||
addOperandElements(opInfo, results);
|
||||
|
||||
+2
-2
@@ -21,7 +21,7 @@ import javax.swing.*;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import ghidra.program.database.DatabaseObject;
|
||||
import ghidra.program.database.DbObject;
|
||||
import ghidra.program.model.data.*;
|
||||
|
||||
public class StructureEditorFlexAlignmentTest extends AbstractStructureEditorTest {
|
||||
@@ -312,7 +312,7 @@ public class StructureEditorFlexAlignmentTest extends AbstractStructureEditorTes
|
||||
private DataTypeComponent addFlexDataType(Structure struct, DataType dataType, String name,
|
||||
String comment) {
|
||||
ArrayDataType a = new ArrayDataType(dataType, 0, 1);
|
||||
if (struct instanceof DatabaseObject) {
|
||||
if (struct instanceof DbObject) {
|
||||
DataTypeManager dtm = struct.getDataTypeManager();
|
||||
return dtm.withTransaction("Add Flex Array", () -> struct.add(a, name, comment));
|
||||
}
|
||||
|
||||
+122
-51
@@ -4,9 +4,9 @@
|
||||
* 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.
|
||||
@@ -17,31 +17,37 @@ package ghidra.program.database;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.ConcurrentModificationException;
|
||||
import java.util.*;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import db.*;
|
||||
import ghidra.program.model.address.KeyRange;
|
||||
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
|
||||
import ghidra.util.Lock;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class ObjectCacheTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
private DBObjectCache<TestObj> cache = new DBObjectCache<TestObj>(100);
|
||||
private DbCache<TestObj> cache;
|
||||
private Lock lock = new Lock("test");
|
||||
private Schema schema;
|
||||
private Map<Long, DBRecord> database = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Constructor for ObjectCacheTest.
|
||||
* @param arg0
|
||||
*/
|
||||
public ObjectCacheTest() {
|
||||
super();
|
||||
@Before
|
||||
public void setUp() {
|
||||
Field[] fields = { new IntField() };
|
||||
String[] fieldNames = { "Value" };
|
||||
|
||||
schema = new Schema(1, "id", fields, fieldNames);
|
||||
cache = new DbCache<TestObj>(new TestFactory(), lock, 100);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetInvalid() {
|
||||
TestObj obj1 = getTestObj(1);
|
||||
obj1.setInvalid();
|
||||
public void testDeleted() {
|
||||
TestObj obj1 = createTestObj(1, 1);
|
||||
deleteTestObj(obj1);
|
||||
try {
|
||||
obj1.setValue(10);
|
||||
fail("Should have thrown a concurrent modification excption here.");
|
||||
@@ -53,8 +59,10 @@ public class ObjectCacheTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
|
||||
@Test
|
||||
public void testDeleteFromCacheSetsDeletedOnObject() {
|
||||
TestObj obj1 = getTestObj(1);
|
||||
TestObj obj1 = createTestObj(1, 1);
|
||||
cache.delete(1);
|
||||
assertFalse(obj1.isValid());
|
||||
|
||||
try {
|
||||
obj1.setValue(10);
|
||||
fail("Should have thrown a concurrent modification excption here.");
|
||||
@@ -66,11 +74,12 @@ public class ObjectCacheTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
|
||||
@Test
|
||||
public void testDeleteUndoProblem() {
|
||||
TestObj obj1 = getTestObj(1);
|
||||
obj1.setInvalid();
|
||||
obj1.checkIsValid();
|
||||
TestObj obj1 = createTestObj(1, 1);
|
||||
deleteTestObj(obj1);
|
||||
assertFalse(obj1.refreshIfNeeded());
|
||||
assertTrue(obj1.isDeleted(lock));
|
||||
|
||||
TestObj obj2 = getTestObj(1);
|
||||
TestObj obj2 = createTestObj(1, 1);
|
||||
assertTrue(obj1 != obj2);
|
||||
|
||||
obj1.getValue(); // previously, this would have caused obj2 to be removed
|
||||
@@ -84,7 +93,7 @@ public class ObjectCacheTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
@Test
|
||||
public void testDeleteRange() {
|
||||
for (int i = 0; i < 10; i++) {
|
||||
getTestObj(i);
|
||||
createTestObj(i, i);
|
||||
}
|
||||
assertEquals(10, cache.size());
|
||||
cache.delete(Arrays.asList(new KeyRange(4, 6)));
|
||||
@@ -94,43 +103,105 @@ public class ObjectCacheTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
@Test
|
||||
public void testDeleteBigRange() {
|
||||
for (int i = 0; i < 10; i++) {
|
||||
getTestObj(i);
|
||||
createTestObj(i, i);
|
||||
}
|
||||
assertEquals(10, cache.size());
|
||||
cache.delete(Arrays.asList(new KeyRange(2, 100)));
|
||||
assertEquals(2, cache.size());
|
||||
}
|
||||
|
||||
private TestObj getTestObj(int key) {
|
||||
TestObj obj = cache.get(key);
|
||||
if (obj == null) {
|
||||
obj = new TestObj(cache, key);
|
||||
@Test
|
||||
public void testRefresh() {
|
||||
TestObj obj1 = createTestObj(1, 1);
|
||||
obj1.setInvalid();
|
||||
assertFalse(obj1.isValid());
|
||||
assertEquals(1, obj1.getValue());
|
||||
assertTrue(obj1.isValid());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvalideCache() {
|
||||
TestObj obj1 = createTestObj(1, 1);
|
||||
TestObj obj2 = createTestObj(2, 2);
|
||||
TestObj obj3 = createTestObj(3, 3);
|
||||
|
||||
assertTrue(obj1.isValid());
|
||||
assertTrue(obj1.isValid());
|
||||
assertTrue(obj1.isValid());
|
||||
|
||||
cache.invalidate();
|
||||
|
||||
assertFalse(obj1.isValid());
|
||||
assertFalse(obj1.isValid());
|
||||
assertFalse(obj1.isValid());
|
||||
|
||||
assertTrue(obj1 == getTestObj(1));
|
||||
assertTrue(obj2 == getTestObj(2));
|
||||
assertTrue(obj3 == getTestObj(3));
|
||||
|
||||
assertTrue(obj1.isValid());
|
||||
assertTrue(obj1.isValid());
|
||||
assertTrue(obj1.isValid());
|
||||
}
|
||||
|
||||
private TestObj createTestObj(long key, int value) {
|
||||
DBRecord record = schema.createRecord(key);
|
||||
record.setIntValue(0, value);
|
||||
database.put(key, record);
|
||||
return cache.getCachedInstance(record);
|
||||
}
|
||||
|
||||
private TestObj getTestObj(long key) {
|
||||
return cache.getCachedInstance(key);
|
||||
}
|
||||
|
||||
private void deleteTestObj(TestObj obj) {
|
||||
database.remove(obj.getKey());
|
||||
obj.setInvalid();
|
||||
}
|
||||
|
||||
class TestFactory implements DbFactory<TestObj> {
|
||||
|
||||
@Override
|
||||
public TestObj instantiate(long key) {
|
||||
DBRecord record = database.get(key);
|
||||
return instantiate(record);
|
||||
}
|
||||
return obj;
|
||||
|
||||
@Override
|
||||
public TestObj instantiate(DBRecord record) {
|
||||
return new TestObj(record);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class TestObj extends DbObject {
|
||||
private DBRecord record;
|
||||
|
||||
TestObj(DBRecord record) {
|
||||
super(record.getKey());
|
||||
this.record = record;
|
||||
}
|
||||
|
||||
public void setValue(int value) {
|
||||
checkDeleted();
|
||||
record.setIntValue(0, value);
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
refreshIfNeeded();
|
||||
return record.getIntValue(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean refresh() {
|
||||
DBRecord refreshedRecord = database.get(record.getKey());
|
||||
if (refreshedRecord != null) {
|
||||
record = refreshedRecord;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class TestObj extends DatabaseObject {
|
||||
int value = -1;
|
||||
|
||||
TestObj(DBObjectCache<TestObj> cache, long key) {
|
||||
super(cache, key);
|
||||
}
|
||||
|
||||
public void setValue(int value) {
|
||||
checkDeleted();
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
checkIsValid();
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean refresh() {
|
||||
// return false to simulate the record has been deleted
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+13
-12
@@ -4,9 +4,9 @@
|
||||
* 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.
|
||||
@@ -20,7 +20,7 @@ import static org.junit.Assert.*;
|
||||
import org.junit.*;
|
||||
|
||||
import ghidra.docking.settings.Settings;
|
||||
import ghidra.program.database.DatabaseObject;
|
||||
import ghidra.program.database.DbObject;
|
||||
import ghidra.program.database.ProgramBuilder;
|
||||
import ghidra.program.database.data.PointerTypedefInspector;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
@@ -96,7 +96,7 @@ public class PointerTypedefDataTypeTest extends AbstractGhidraHeadedIntegrationT
|
||||
assertEquals("char * " + formatAttributes("offset(0x8)"), dt.getName());
|
||||
DataType dbDt = dtm.resolve(dt, null);
|
||||
assertTrue(dbDt instanceof TypeDef);
|
||||
assertTrue(dbDt instanceof DatabaseObject); // transforms to TypedefDB
|
||||
assertTrue(dbDt instanceof DbObject); // transforms to TypedefDB
|
||||
assertTrue(dt.isEquivalent(dbDt));
|
||||
assertEquals(dt.getName(), dbDt.getName());
|
||||
|
||||
@@ -112,7 +112,7 @@ public class PointerTypedefDataTypeTest extends AbstractGhidraHeadedIntegrationT
|
||||
assertEquals("char * " + formatAttributes("relative"), dt.getName());
|
||||
dbDt = dtm.resolve(dt, null);
|
||||
assertTrue(dbDt instanceof TypeDef);
|
||||
assertTrue(dbDt instanceof DatabaseObject); // transforms to TypedefDB
|
||||
assertTrue(dbDt instanceof DbObject); // transforms to TypedefDB
|
||||
assertTrue(dt.isEquivalent(dbDt));
|
||||
assertEquals(dt.getName(), dbDt.getName());
|
||||
|
||||
@@ -131,7 +131,7 @@ public class PointerTypedefDataTypeTest extends AbstractGhidraHeadedIntegrationT
|
||||
assertEquals("char *16 " + formatAttributes("space(register)"), dt.getName());
|
||||
DataType dbDt = dtm.resolve(dt, null);
|
||||
assertTrue(dbDt instanceof TypeDef);
|
||||
assertTrue(dbDt instanceof DatabaseObject); // transforms to TypedefDB
|
||||
assertTrue(dbDt instanceof DbObject); // transforms to TypedefDB
|
||||
assertTrue(dt.isEquivalent(dbDt));
|
||||
assertEquals(dt.getName(), dbDt.getName());
|
||||
|
||||
@@ -147,7 +147,7 @@ public class PointerTypedefDataTypeTest extends AbstractGhidraHeadedIntegrationT
|
||||
assertEquals("char *32 " + formatAttributes("space(register)"), dt.getName());
|
||||
dbDt = dtm.resolve(dt, null);
|
||||
assertTrue(dbDt instanceof TypeDef);
|
||||
assertTrue(dbDt instanceof DatabaseObject); // transforms to TypedefDB
|
||||
assertTrue(dbDt instanceof DbObject); // transforms to TypedefDB
|
||||
assertTrue(dt.isEquivalent(dbDt));
|
||||
assertEquals(dt.getName(), dbDt.getName());
|
||||
|
||||
@@ -169,7 +169,7 @@ public class PointerTypedefDataTypeTest extends AbstractGhidraHeadedIntegrationT
|
||||
assertEquals("foo *16 " + formatAttributes("space(register)"), dt.getName());
|
||||
DataType dbDt = dtm.resolve(dt, null);
|
||||
assertTrue(dbDt instanceof TypeDef);
|
||||
assertTrue(dbDt instanceof DatabaseObject); // transforms to TypedefDB
|
||||
assertTrue(dbDt instanceof DbObject); // transforms to TypedefDB
|
||||
assertTrue(dt.isEquivalent(dbDt));
|
||||
assertEquals(dt.getName(), dbDt.getName());
|
||||
|
||||
@@ -244,7 +244,7 @@ public class PointerTypedefDataTypeTest extends AbstractGhidraHeadedIntegrationT
|
||||
assertEquals(2, dt.getLength());
|
||||
assertEquals("foo *16 " + formatAttributes("space(register)"), dt.getName());
|
||||
TypeDef dbDt = (TypeDef) dtm.resolve(dt, null);
|
||||
assertTrue(dbDt instanceof DatabaseObject); // transforms to TypedefDB
|
||||
assertTrue(dbDt instanceof DbObject); // transforms to TypedefDB
|
||||
assertTrue(dt.isEquivalent(dbDt));
|
||||
assertEquals(dt.getName(), dbDt.getName());
|
||||
|
||||
@@ -252,7 +252,8 @@ public class PointerTypedefDataTypeTest extends AbstractGhidraHeadedIntegrationT
|
||||
assertTrue(dbDt == dtm.resolve(dt, null)); // should resolve to same instance
|
||||
|
||||
dt = (TypeDef) dt.copy(dtm);
|
||||
PointerTypeSettingsDefinition.DEF.setType(dt.getDefaultSettings(), PointerType.IMAGE_BASE_RELATIVE);
|
||||
PointerTypeSettingsDefinition.DEF.setType(dt.getDefaultSettings(),
|
||||
PointerType.IMAGE_BASE_RELATIVE);
|
||||
TypeDef dbDt2 = (TypeDef) dtm.resolve(dt, null); // should resolve to new instance
|
||||
assertTrue(dbDt != dbDt2);
|
||||
assertEquals("foo *16 " + formatAttributes("image-base-relative,space(register)"),
|
||||
@@ -276,7 +277,7 @@ public class PointerTypedefDataTypeTest extends AbstractGhidraHeadedIntegrationT
|
||||
assertEquals(2, dt.getLength());
|
||||
assertEquals("foo *16 " + formatAttributes("space(register)"), dt.getName());
|
||||
TypeDef dbDt = (TypeDef) dtm.resolve(dt, null);
|
||||
assertTrue(dbDt instanceof DatabaseObject); // transforms to TypedefDB
|
||||
assertTrue(dbDt instanceof DbObject); // transforms to TypedefDB
|
||||
assertTrue(dt.isEquivalent(dbDt));
|
||||
assertEquals(dt.getName(), dbDt.getName());
|
||||
|
||||
@@ -290,7 +291,7 @@ public class PointerTypedefDataTypeTest extends AbstractGhidraHeadedIntegrationT
|
||||
assertTrue(dbDt != dbDt2);
|
||||
assertFalse(dbDt.isEquivalent(dbDt2));
|
||||
assertFalse(dbDt2.isEquivalent(dbDt));
|
||||
assertTrue(dbDt2 instanceof DatabaseObject); // transforms to TypedefDB
|
||||
assertTrue(dbDt2 instanceof DbObject); // transforms to TypedefDB
|
||||
assertTrue(dt2.isEquivalent(dbDt2));
|
||||
assertEquals(dt2.getName(), dbDt2.getName());
|
||||
|
||||
|
||||
+3
-11
@@ -37,6 +37,7 @@ import ghidra.program.model.util.CodeUnitInsertionException;
|
||||
import ghidra.program.model.util.PropertyMap;
|
||||
import ghidra.test.ToyProgramBuilder;
|
||||
import ghidra.util.Lock;
|
||||
import ghidra.util.Lock.Closeable;
|
||||
import ghidra.util.SaveableColor;
|
||||
import ghidra.util.exception.NoValueException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
@@ -992,8 +993,7 @@ public class CodeManagerTest extends AbstractGenericTest {
|
||||
ProgramDB pdb = (ProgramDB) program;
|
||||
Lock lock = pdb.getLock();
|
||||
|
||||
lock.acquire();
|
||||
try {
|
||||
try (Closeable c = lock.write()) {
|
||||
|
||||
Instruction instructionAt = pdb.getListing().getInstructionAt(addr(0x2000));
|
||||
assertEquals(FlowOverride.NONE, instructionAt.getFlowOverride());
|
||||
@@ -1007,9 +1007,6 @@ public class CodeManagerTest extends AbstractGenericTest {
|
||||
instructionAt = pdb.getListing().getInstructionAt(addr(0x2000));
|
||||
assertEquals(FlowOverride.CALL, instructionAt.getFlowOverride());
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1020,9 +1017,7 @@ public class CodeManagerTest extends AbstractGenericTest {
|
||||
ProgramDB pdb = (ProgramDB) program;
|
||||
Lock lock = pdb.getLock();
|
||||
|
||||
lock.acquire();
|
||||
try {
|
||||
|
||||
try (Closeable c = lock.write()) {
|
||||
Instruction instructionAt = pdb.getListing().getInstructionAt(addr(0x2000));
|
||||
assertEquals(FlowOverride.NONE, instructionAt.getFlowOverride());
|
||||
|
||||
@@ -1031,9 +1026,6 @@ public class CodeManagerTest extends AbstractGenericTest {
|
||||
instructionAt = pdb.getListing().getInstructionAt(addr(0x2002));
|
||||
assertEquals(null, instructionAt);
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
private Address addr(long l) {
|
||||
|
||||
+4
-4
@@ -4,9 +4,9 @@
|
||||
* 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.
|
||||
@@ -79,12 +79,12 @@ public class DefaultDataCacheTest extends AbstractGenericTest {
|
||||
assertTrue(cu instanceof Data);
|
||||
DataDB data = (DataDB) cu;
|
||||
assertTrue(!data.isDefined());
|
||||
assertTrue(!((Boolean) invokeInstanceMethod("isInvalid", data)));
|
||||
assertFalse((Boolean) invokeInstanceMethod("needsRefreshing", data));
|
||||
AddressSet restrictedSet = new AddressSet(addr(0x1000), addr(0x1003));
|
||||
Disassembler disassembler = Disassembler.getDisassembler(program, TaskMonitor.DUMMY, null);
|
||||
AddressSetView disAddrs = disassembler.disassemble(addr(0x1000), restrictedSet);
|
||||
assertTrue(!disAddrs.isEmpty());
|
||||
assertTrue(!((Boolean) invokeInstanceMethod("checkIsValid", data)));
|
||||
assertFalse((Boolean) invokeInstanceMethod("needsRefreshing", data));
|
||||
assertNull(listing.getCodeUnitAt(addr(0x1001)));
|
||||
}
|
||||
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
* 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.
|
||||
@@ -19,14 +19,13 @@ import static ghidra.feature.fid.db.FunctionsTable.*;
|
||||
|
||||
import db.DBRecord;
|
||||
import ghidra.feature.fid.hash.FidHashQuad;
|
||||
import ghidra.program.database.DBObjectCache;
|
||||
import ghidra.program.database.DatabaseObject;
|
||||
import ghidra.program.database.DbObject;
|
||||
import ghidra.util.NumericUtilities;
|
||||
|
||||
/**
|
||||
* Represents a function record in the FID database.
|
||||
*/
|
||||
public class FunctionRecord extends DatabaseObject implements FidHashQuad {
|
||||
public class FunctionRecord extends DbObject implements FidHashQuad {
|
||||
public final static int HAS_TERMINATOR_FLAG = 1;
|
||||
public final static int AUTO_PASS_FLAG = 2;
|
||||
public final static int AUTO_FAIL_FLAG = 4;
|
||||
@@ -46,11 +45,10 @@ public class FunctionRecord extends DatabaseObject implements FidHashQuad {
|
||||
/**
|
||||
* Package private constructor, to be called from FunctionsTable exclusively.
|
||||
* @param fid database (for string references)
|
||||
* @param cache FunctionRecord object cache
|
||||
* @param record record for this function
|
||||
*/
|
||||
FunctionRecord(FidDB fid, DBObjectCache<FunctionRecord> cache, DBRecord record) {
|
||||
super(cache, record.getKey());
|
||||
FunctionRecord(FidDB fid, DBRecord record) {
|
||||
super(record.getKey());
|
||||
this.record = record;
|
||||
this.fidDb = fid;
|
||||
}
|
||||
@@ -169,6 +167,7 @@ public class FunctionRecord extends DatabaseObject implements FidHashQuad {
|
||||
byte val = record.getByteValue(FLAGS_COL);
|
||||
return ((val & FORCE_RELATION_FLAG) != 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the record id (primary key).
|
||||
* @return the record id
|
||||
|
||||
+49
-89
@@ -4,9 +4,9 @@
|
||||
* 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.
|
||||
@@ -22,7 +22,9 @@ import java.util.regex.Pattern;
|
||||
|
||||
import db.*;
|
||||
import ghidra.feature.fid.hash.FidHashQuad;
|
||||
import ghidra.program.database.DBObjectCache;
|
||||
import ghidra.program.database.DbFactory;
|
||||
import ghidra.program.database.DbCache;
|
||||
import ghidra.util.Lock;
|
||||
import ghidra.util.UniversalIdGenerator;
|
||||
|
||||
/**
|
||||
@@ -62,20 +64,19 @@ public class FunctionsTable {
|
||||
Table table;
|
||||
FidDB fidDb;
|
||||
StringsTable stringsTable;
|
||||
DBObjectCache<FunctionRecord> functionCache;
|
||||
DbCache<FunctionRecord> functionCache;
|
||||
|
||||
/**
|
||||
* Creates or attaches a functions table.
|
||||
* @param fid the fid database
|
||||
* @param handle database handle
|
||||
* @param stringsTable strings table (must be created first!)
|
||||
* @param create whether to create or just attach
|
||||
* @throws IOException if create fails
|
||||
*/
|
||||
public FunctionsTable(FidDB fid, DBHandle handle) throws IOException {
|
||||
table = handle.getTable(FUNCTIONS_TABLE);
|
||||
this.fidDb = fid;
|
||||
this.stringsTable = fid.getStringsTable();
|
||||
functionCache = new DBObjectCache<>(CACHE_SIZE);
|
||||
functionCache = new DbCache<>(new FunctionRecordFactory(), new Lock("Fid"), CACHE_SIZE);
|
||||
}
|
||||
|
||||
public static void createTable(DBHandle handle) throws IOException {
|
||||
@@ -116,11 +117,7 @@ public class FunctionsTable {
|
||||
if (record.getLongValue(SPECIFIC_HASH_COL) != hash) {
|
||||
continue;
|
||||
}
|
||||
FunctionRecord functionRecord = functionCache.get(record);
|
||||
if (functionRecord == null) {
|
||||
functionRecord = new FunctionRecord(fidDb, functionCache, record);
|
||||
}
|
||||
list.add(functionRecord);
|
||||
list.add(functionCache.getCachedInstance(record));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
@@ -141,12 +138,10 @@ public class FunctionsTable {
|
||||
List<FunctionRecord> list = new ArrayList<>();
|
||||
while (iterator.hasNext()) {
|
||||
Field key = iterator.next();
|
||||
FunctionRecord functionRecord = functionCache.get(key.getLongValue());
|
||||
if (functionRecord == null) {
|
||||
DBRecord record = table.getRecord(key);
|
||||
functionRecord = new FunctionRecord(fidDb, functionCache, record);
|
||||
FunctionRecord functionRecord = functionCache.getCachedInstance(key.getLongValue());
|
||||
if (functionRecord != null) {
|
||||
list.add(functionRecord);
|
||||
}
|
||||
list.add(functionRecord);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
@@ -179,7 +174,8 @@ public class FunctionsTable {
|
||||
byte flags = (byte) (hasTerminator ? FunctionRecord.HAS_TERMINATOR_FLAG : 0);
|
||||
record.setByteValue(FLAGS_COL, flags);
|
||||
table.putRecord(record);
|
||||
FunctionRecord functionRecord = new FunctionRecord(fidDb, functionCache, record);
|
||||
FunctionRecord functionRecord = new FunctionRecord(fidDb, record);
|
||||
functionCache.add(functionRecord);
|
||||
return functionRecord;
|
||||
}
|
||||
|
||||
@@ -188,7 +184,7 @@ public class FunctionsTable {
|
||||
* @param functionID is the id of the function record to modify
|
||||
* @param flagMask is the bit to modify
|
||||
* @param value is true to set, false to clear
|
||||
* @throws IOException
|
||||
* @throws IOException if error occurs while reading database
|
||||
*/
|
||||
void modifyFlags(long functionID, int flagMask, boolean value) throws IOException {
|
||||
DBRecord record = table.getRecord(functionID);
|
||||
@@ -217,30 +213,12 @@ public class FunctionsTable {
|
||||
*/
|
||||
public List<FunctionRecord> getFunctionRecordsByNameSubstring(String nameSearch)
|
||||
throws IOException {
|
||||
DBFieldIterator iterator = table.indexKeyIterator(NAME_ID_COL);
|
||||
|
||||
if (!iterator.hasNext()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<FunctionRecord> list = new ArrayList<>();
|
||||
RecordIterator iterator = table.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Field key = iterator.next();
|
||||
FunctionRecord functionRecord = functionCache.get(key.getLongValue());
|
||||
if (functionRecord == null) {
|
||||
DBRecord record = table.getRecord(key);
|
||||
long nameID = record.getLongValue(NAME_ID_COL);
|
||||
StringRecord nameRecord = stringsTable.lookupString(nameID);
|
||||
String name = nameRecord.getValue();
|
||||
if (name.contains(nameSearch)) {
|
||||
functionRecord = new FunctionRecord(fidDb, functionCache, record);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!functionRecord.getName().contains(nameSearch)) {
|
||||
functionRecord = null;
|
||||
}
|
||||
}
|
||||
if (functionRecord != null) {
|
||||
DBRecord record = iterator.next();
|
||||
FunctionRecord functionRecord = functionCache.getCachedInstance(record);
|
||||
if (functionRecord.getName().contains(nameSearch)) {
|
||||
list.add(functionRecord);
|
||||
}
|
||||
}
|
||||
@@ -256,32 +234,14 @@ public class FunctionsTable {
|
||||
*/
|
||||
public List<FunctionRecord> getFunctionRecordsByNameRegex(String regex) throws IOException {
|
||||
Matcher matcher = Pattern.compile(regex).matcher("");
|
||||
DBFieldIterator iterator = table.indexKeyIterator(NAME_ID_COL);
|
||||
|
||||
if (!iterator.hasNext()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<FunctionRecord> list = new ArrayList<>();
|
||||
RecordIterator iterator = table.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Field key = iterator.next();
|
||||
FunctionRecord functionRecord = functionCache.get(key.getLongValue());
|
||||
if (functionRecord == null) {
|
||||
DBRecord record = table.getRecord(key);
|
||||
long nameID = record.getLongValue(NAME_ID_COL);
|
||||
StringRecord nameRecord = stringsTable.lookupString(nameID);
|
||||
String name = nameRecord.getValue();
|
||||
matcher.reset(name);
|
||||
if (matcher.matches()) {
|
||||
functionRecord = new FunctionRecord(fidDb, functionCache, record);
|
||||
}
|
||||
}
|
||||
else {
|
||||
matcher.reset(functionRecord.getName());
|
||||
if (!matcher.matches()) {
|
||||
functionRecord = null;
|
||||
}
|
||||
}
|
||||
if (functionRecord != null) {
|
||||
DBRecord record = iterator.next();
|
||||
FunctionRecord functionRecord = functionCache.getCachedInstance(record);
|
||||
matcher.reset(functionRecord.getName());
|
||||
if (matcher.matches()) {
|
||||
list.add(functionRecord);
|
||||
}
|
||||
}
|
||||
@@ -295,14 +255,7 @@ public class FunctionsTable {
|
||||
* @throws IOException if database seek encounters an error
|
||||
*/
|
||||
public FunctionRecord getFunctionByID(long functionID) throws IOException {
|
||||
FunctionRecord functionRecord = functionCache.get(functionID);
|
||||
if (functionRecord == null) {
|
||||
DBRecord record = table.getRecord(functionID);
|
||||
if (record != null) {
|
||||
functionRecord = new FunctionRecord(fidDb, functionCache, record);
|
||||
}
|
||||
}
|
||||
return functionRecord;
|
||||
return functionCache.getCachedInstance(functionID);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -323,11 +276,7 @@ public class FunctionsTable {
|
||||
StringRecord domainPathRecord = stringsTable.lookupString(domainPathID);
|
||||
String domainPath = domainPathRecord.getValue();
|
||||
if (domainPath.contains(domainPathSearch)) {
|
||||
FunctionRecord functionRecord = functionCache.get(record);
|
||||
if (functionRecord == null) {
|
||||
functionRecord = new FunctionRecord(fidDb, functionCache, record);
|
||||
}
|
||||
list.add(functionRecord);
|
||||
list.add(functionCache.getCachedInstance(record));
|
||||
}
|
||||
}
|
||||
return list;
|
||||
@@ -356,20 +305,31 @@ public class FunctionsTable {
|
||||
List<FunctionRecord> list = new ArrayList<>();
|
||||
while (iterator.hasNext()) {
|
||||
Field key = iterator.next();
|
||||
FunctionRecord functionRecord = functionCache.get(key.getLongValue());
|
||||
if (functionRecord == null) {
|
||||
DBRecord record = table.getRecord(key);
|
||||
if (record.getLongValue(LIBRARY_ID_COL) == libraryKey) {
|
||||
functionRecord = new FunctionRecord(fidDb, functionCache, record);
|
||||
list.add(functionRecord);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (functionRecord.getLibraryID() == libraryKey) {
|
||||
list.add(functionRecord);
|
||||
}
|
||||
FunctionRecord functionRecord = functionCache.getCachedInstance(key.getLongValue());
|
||||
if (functionRecord.getLibraryID() == libraryKey) {
|
||||
list.add(functionRecord);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
class FunctionRecordFactory implements DbFactory<FunctionRecord> {
|
||||
|
||||
@Override
|
||||
public FunctionRecord instantiate(long key) {
|
||||
try {
|
||||
DBRecord record = table.getRecord(key);
|
||||
return record == null ? null : instantiate(record);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new RuntimeException("serious delayed database access error", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public FunctionRecord instantiate(DBRecord record) {
|
||||
return new FunctionRecord(fidDb, record);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
* 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.
|
||||
@@ -15,13 +15,12 @@
|
||||
*/
|
||||
package ghidra.feature.fid.db;
|
||||
|
||||
import ghidra.program.database.DBObjectCache;
|
||||
import ghidra.program.database.DatabaseObject;
|
||||
import ghidra.program.database.DbObject;
|
||||
|
||||
/**
|
||||
* A string record in the FID database.
|
||||
*/
|
||||
public class StringRecord extends DatabaseObject {
|
||||
public class StringRecord extends DbObject {
|
||||
/**
|
||||
* The value of the string.
|
||||
*/
|
||||
@@ -29,12 +28,11 @@ public class StringRecord extends DatabaseObject {
|
||||
|
||||
/**
|
||||
* Constructor with the primary key and the string value.
|
||||
* @param cache StringRecord object cache
|
||||
* @param key primary key
|
||||
* @param value the string value
|
||||
*/
|
||||
public StringRecord(DBObjectCache<StringRecord> cache, long key, String value) {
|
||||
super(cache, key);
|
||||
public StringRecord(long key, String value) {
|
||||
super(key);
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
* 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.
|
||||
@@ -18,7 +18,9 @@ package ghidra.feature.fid.db;
|
||||
import java.io.IOException;
|
||||
|
||||
import db.*;
|
||||
import ghidra.program.database.DBObjectCache;
|
||||
import ghidra.program.database.DbFactory;
|
||||
import ghidra.program.database.DbCache;
|
||||
import ghidra.util.Lock;
|
||||
import ghidra.util.UniversalIdGenerator;
|
||||
|
||||
/**
|
||||
@@ -43,17 +45,16 @@ public class StringsTable {
|
||||
static int[] INDEXED_COLUMNS = new int[] { STRING_VALUE_COL };
|
||||
|
||||
Table table;
|
||||
DBObjectCache<StringRecord> stringCache;
|
||||
DbCache<StringRecord> stringCache;
|
||||
|
||||
/**
|
||||
* Creates or attaches the string table.
|
||||
* @param handle the database handle
|
||||
* @param create whether to create or attach
|
||||
* @throws IOException if the database has a problem
|
||||
*/
|
||||
public StringsTable(DBHandle handle) throws IOException {
|
||||
table = handle.getTable(STRINGS_TABLE);
|
||||
stringCache = new DBObjectCache<>(CACHE_SIZE);
|
||||
stringCache = new DbCache<>(new StringRecordFactory(), new Lock("Fid"), CACHE_SIZE);
|
||||
}
|
||||
|
||||
public static void createTable(DBHandle handle) throws IOException {
|
||||
@@ -99,20 +100,25 @@ public class StringsTable {
|
||||
* @return the string record, or null if no such key
|
||||
*/
|
||||
StringRecord lookupString(long stringID) {
|
||||
StringRecord stringRecord = stringCache.get(stringID);
|
||||
if (stringRecord == null) {
|
||||
DBRecord record;
|
||||
return stringCache.getCachedInstance(stringID);
|
||||
}
|
||||
|
||||
class StringRecordFactory implements DbFactory<StringRecord> {
|
||||
|
||||
@Override
|
||||
public StringRecord instantiate(long key) {
|
||||
try {
|
||||
record = table.getRecord(stringID);
|
||||
if (record != null) {
|
||||
stringRecord =
|
||||
new StringRecord(stringCache, stringID, record.getString(STRING_VALUE_COL));
|
||||
}
|
||||
DBRecord record = table.getRecord(key);
|
||||
return record == null ? null : instantiate(record);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new RuntimeException("serious delayed database access error", e);
|
||||
}
|
||||
}
|
||||
return stringRecord;
|
||||
|
||||
@Override
|
||||
public StringRecord instantiate(DBRecord record) {
|
||||
return new StringRecord(record.getKey(), record.getString(STRING_VALUE_COL));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+81
-133
@@ -4,9 +4,9 @@
|
||||
* 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.
|
||||
@@ -25,9 +25,11 @@ import ghidra.feature.vt.api.impl.*;
|
||||
import ghidra.feature.vt.api.main.*;
|
||||
import ghidra.feature.vt.api.util.VTAssociationStatusException;
|
||||
import ghidra.framework.data.OpenMode;
|
||||
import ghidra.program.database.DBObjectCache;
|
||||
import ghidra.program.database.DbFactory;
|
||||
import ghidra.program.database.DbCache;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.util.Lock;
|
||||
import ghidra.util.Lock.Closeable;
|
||||
import ghidra.util.exception.*;
|
||||
import ghidra.util.task.TaskLauncher;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
@@ -39,9 +41,9 @@ public class AssociationDatabaseManager implements VTAssociationManager {
|
||||
private VTAssociationTableDBAdapter associationTableAdapter;
|
||||
|
||||
private VTMatchMarkupItemTableDBAdapter markupItemTableAdapter;
|
||||
private DBObjectCache<MarkupItemStorageDB> markupItemCache;
|
||||
private DbCache<MarkupItemStorageDB> markupItemCache;
|
||||
private List<AssociationHook> associationHooks = new ArrayList<>();
|
||||
private DBObjectCache<VTAssociationDB> associationCache;
|
||||
private DbCache<VTAssociationDB> associationCache;
|
||||
private AcceptedStatusCache acceptedStatusCache = new AcceptedStatusCache();
|
||||
Lock lock;
|
||||
|
||||
@@ -67,8 +69,8 @@ public class AssociationDatabaseManager implements VTAssociationManager {
|
||||
AssociationDatabaseManager(VTSessionDB session) {
|
||||
this.session = session;
|
||||
lock = session.getLock();
|
||||
associationCache = new DBObjectCache<>(10);
|
||||
markupItemCache = new DBObjectCache<>(10);
|
||||
associationCache = new DbCache<>(new AssociationFactory(), lock, 10);
|
||||
markupItemCache = new DbCache<>(new MarkupFactory(), lock, 10);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -84,8 +86,7 @@ public class AssociationDatabaseManager implements VTAssociationManager {
|
||||
|
||||
Collection<MarkupItemStorageDB> items = new ArrayList<>();
|
||||
VTAssociationDB associationDB = (VTAssociationDB) association;
|
||||
try {
|
||||
lock.acquire();
|
||||
try (Closeable c = lock.read()) {
|
||||
int recordCount = markupItemTableAdapter.getRecordCount();
|
||||
if (recordCount == 0) {
|
||||
recordCount = 1; // to give the appearance of progress
|
||||
@@ -98,7 +99,7 @@ public class AssociationDatabaseManager implements VTAssociationManager {
|
||||
while (records.hasNext()) {
|
||||
monitor.checkCancelled();
|
||||
DBRecord record = records.next();
|
||||
items.add(getMarkupItemForRecord(record));
|
||||
items.add(markupItemCache.getCachedInstance(record));
|
||||
monitor.incrementProgress(1);
|
||||
}
|
||||
|
||||
@@ -107,9 +108,6 @@ public class AssociationDatabaseManager implements VTAssociationManager {
|
||||
catch (IOException e) {
|
||||
session.dbError(e);
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
@@ -148,20 +146,6 @@ public class AssociationDatabaseManager implements VTAssociationManager {
|
||||
}
|
||||
}
|
||||
|
||||
private MarkupItemStorageDB getMarkupItemForRecord(DBRecord markupItemRecord) {
|
||||
try {
|
||||
lock.acquire();
|
||||
MarkupItemStorageDB markupItem = markupItemCache.get(markupItemRecord);
|
||||
if (markupItem == null) {
|
||||
markupItem = new MarkupItemStorageDB(markupItemRecord, markupItemCache, this);
|
||||
}
|
||||
return markupItem;
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
Address getDestinationAddressFromLong(long longValue) {
|
||||
return session.getDestinationAddressFromLong(longValue);
|
||||
}
|
||||
@@ -188,7 +172,8 @@ public class AssociationDatabaseManager implements VTAssociationManager {
|
||||
|
||||
try {
|
||||
DBRecord record = markupItemTableAdapter.createMarkupItemRecord(markupItem);
|
||||
MarkupItemStorageDB appliedMarkupItem = getMarkupItemForRecord(record);
|
||||
MarkupItemStorageDB appliedMarkupItem = new MarkupItemStorageDB(record, this);
|
||||
markupItemCache.add(appliedMarkupItem);
|
||||
return appliedMarkupItem;
|
||||
}
|
||||
catch (IOException e) {
|
||||
@@ -213,18 +198,15 @@ public class AssociationDatabaseManager implements VTAssociationManager {
|
||||
boolean isBlocked = isBlocked(sourceAddress, destinationAddress);
|
||||
|
||||
VTAssociationDB newAssociation = null;
|
||||
try {
|
||||
lock.acquire();
|
||||
try (Closeable c = lock.write()) {
|
||||
DBRecord record = associationTableAdapter.insertRecord(sourceLong, destinationLong,
|
||||
type, isBlocked ? BLOCKED : AVAILABLE, 0);
|
||||
newAssociation = new VTAssociationDB(this, associationCache, record);
|
||||
newAssociation = new VTAssociationDB(this, record);
|
||||
associationCache.add(newAssociation);
|
||||
}
|
||||
catch (IOException e) {
|
||||
session.dbError(e);
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
session.setChanged(VTEvent.ASSOCIATION_ADDED, null, newAssociation);
|
||||
return newAssociation;
|
||||
}
|
||||
@@ -274,33 +256,28 @@ public class AssociationDatabaseManager implements VTAssociationManager {
|
||||
@Override
|
||||
public List<VTAssociation> getAssociations() {
|
||||
List<VTAssociation> list = new ArrayList<>();
|
||||
lock.acquire();
|
||||
try {
|
||||
try (Closeable c = lock.read()) {
|
||||
RecordIterator iterator = associationTableAdapter.getRecords();
|
||||
for (; iterator.hasNext();) {
|
||||
DBRecord nextRecord = iterator.next();
|
||||
list.add(getAssociationForRecord(nextRecord));
|
||||
list.add(associationCache.getCachedInstance(nextRecord));
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
session.dbError(e);
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VTAssociation getAssociation(Address sourceAddress, Address destinationAddress) {
|
||||
lock.acquire();
|
||||
try {
|
||||
try (Closeable c = lock.read()) {
|
||||
long addressKey = session.getLongFromSourceAddress(sourceAddress);
|
||||
RecordIterator iterator =
|
||||
associationTableAdapter.getRecordsForSourceAddress(addressKey);
|
||||
while (iterator.hasNext()) {
|
||||
DBRecord record = iterator.next();
|
||||
VTAssociationDB associationDB = getAssociationForRecord(record);
|
||||
VTAssociationDB associationDB = associationCache.getCachedInstance(record);
|
||||
if (associationDB.getDestinationAddress().equals(destinationAddress)) {
|
||||
return associationDB;
|
||||
}
|
||||
@@ -309,9 +286,6 @@ public class AssociationDatabaseManager implements VTAssociationManager {
|
||||
catch (IOException e) {
|
||||
session.dbError(e);
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -323,7 +297,7 @@ public class AssociationDatabaseManager implements VTAssociationManager {
|
||||
associationTableAdapter.getRecordsForSourceAddress(addressKey);
|
||||
while (iterator.hasNext()) {
|
||||
DBRecord record = iterator.next();
|
||||
VTAssociationDB associationDB = getAssociationForRecord(record);
|
||||
VTAssociationDB associationDB = associationCache.getCachedInstance(record);
|
||||
Address dbDestinatonAddress = associationDB.getDestinationAddress();
|
||||
if (destinationAddress.equals(dbDestinatonAddress)) {
|
||||
return associationDB;
|
||||
@@ -337,99 +311,51 @@ public class AssociationDatabaseManager implements VTAssociationManager {
|
||||
return null;
|
||||
}
|
||||
|
||||
private VTAssociationDB getAssociationForRecord(DBRecord record) {
|
||||
if (record == null) {
|
||||
throw new AssertException("How can we have a null record?!!!");
|
||||
}
|
||||
try {
|
||||
lock.acquire();
|
||||
VTAssociationDB associationDB = associationCache.get(record);
|
||||
if (associationDB == null) {
|
||||
associationDB = new VTAssociationDB(this, associationCache, record);
|
||||
}
|
||||
return associationDB;
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
VTAssociationDB getAssociation(long associationKey) {
|
||||
try {
|
||||
lock.acquire();
|
||||
VTAssociationDB associationDB = associationCache.get(associationKey);
|
||||
if (associationDB != null) {
|
||||
return associationDB;
|
||||
}
|
||||
DBRecord record = associationTableAdapter.getRecord(associationKey);
|
||||
if (record == null) {
|
||||
return null;
|
||||
}
|
||||
return new VTAssociationDB(this, associationCache, record);
|
||||
}
|
||||
catch (IOException e) {
|
||||
session.dbError(e);
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public VTSessionDB getSession() {
|
||||
return session;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<VTAssociation> getRelatedAssociationsBySourceAddress(Address sourceAddress) {
|
||||
lock.acquire();
|
||||
try {
|
||||
try (Closeable c = lock.read()) {
|
||||
long sourceId = session.getLongFromSourceAddress(sourceAddress);
|
||||
Set<DBRecord> relatedRecords =
|
||||
associationTableAdapter.getRelatedAssociationRecordsBySourceAddress(sourceId);
|
||||
List<VTAssociation> associations = new ArrayList<>();
|
||||
for (DBRecord record : relatedRecords) {
|
||||
associations.add(getAssociationForRecord(record));
|
||||
associations.add(associationCache.getCachedInstance(record));
|
||||
}
|
||||
return associations;
|
||||
}
|
||||
catch (IOException e) {
|
||||
session.dbError(e);
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<VTAssociation> getRelatedAssociationsByDestinationAddress(
|
||||
Address destinationAddress) {
|
||||
lock.acquire();
|
||||
try {
|
||||
try (Closeable c = lock.read()) {
|
||||
long destinationId = session.getLongFromDestinationAddress(destinationAddress);
|
||||
Set<DBRecord> relatedRecords = associationTableAdapter
|
||||
.getRelatedAssociationRecordsByDestinationAddress(destinationId);
|
||||
List<VTAssociation> associations = new ArrayList<>();
|
||||
for (DBRecord record : relatedRecords) {
|
||||
associations.add(getAssociationForRecord(record));
|
||||
associations.add(associationCache.getCachedInstance(record));
|
||||
}
|
||||
return associations;
|
||||
}
|
||||
catch (IOException e) {
|
||||
session.dbError(e);
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<VTAssociation> getRelatedAssociationsBySourceAndDestinationAddress(
|
||||
Address sourceAddress, Address destinationAddress) {
|
||||
lock.acquire();
|
||||
try {
|
||||
try (Closeable c = lock.read()) {
|
||||
long sourceId = session.getLongFromSourceAddress(sourceAddress);
|
||||
long destinationId = session.getLongFromDestinationAddress(destinationAddress);
|
||||
Set<DBRecord> relatedRecords =
|
||||
@@ -437,16 +363,13 @@ public class AssociationDatabaseManager implements VTAssociationManager {
|
||||
sourceId, destinationId);
|
||||
List<VTAssociation> associations = new ArrayList<>();
|
||||
for (DBRecord record : relatedRecords) {
|
||||
associations.add(getAssociationForRecord(record));
|
||||
associations.add(associationCache.getCachedInstance(record));
|
||||
}
|
||||
return associations;
|
||||
}
|
||||
catch (IOException e) {
|
||||
session.dbError(e);
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@@ -564,7 +487,7 @@ public class AssociationDatabaseManager implements VTAssociationManager {
|
||||
sourceId, destinationId);
|
||||
relatedRecords.remove(association.getRecord()); // don't change the given association
|
||||
for (DBRecord record : relatedRecords) {
|
||||
relatedAssociaitons.add(getAssociationForRecord(record));
|
||||
relatedAssociaitons.add(associationCache.getCachedInstance(record));
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
@@ -581,7 +504,7 @@ public class AssociationDatabaseManager implements VTAssociationManager {
|
||||
session.dbError(e);
|
||||
}
|
||||
|
||||
VTAssociationDB association = getAssociationForRecord(record);
|
||||
VTAssociationDB association = associationCache.getCachedInstance(record);
|
||||
Address sourceAddress = association.getSourceAddress();
|
||||
Address destinationAddress = association.getDestinationAddress();
|
||||
VTAssociationStatus status = association.getStatus();
|
||||
@@ -619,6 +542,7 @@ public class AssociationDatabaseManager implements VTAssociationManager {
|
||||
void removeMarkupRecord(long key) {
|
||||
try {
|
||||
markupItemTableAdapter.removeMarkupItemRecord(key);
|
||||
markupItemCache.delete(key);
|
||||
}
|
||||
catch (IOException e) {
|
||||
session.dbError(e);
|
||||
@@ -661,60 +585,43 @@ public class AssociationDatabaseManager implements VTAssociationManager {
|
||||
private boolean disposed = false;
|
||||
|
||||
void dispose() {
|
||||
lock.acquire();
|
||||
try {
|
||||
try (Closeable c = lock.write()) {
|
||||
disposed = true;
|
||||
invalidate();
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
void invalidate() {
|
||||
lock.acquire();
|
||||
try {
|
||||
try (Closeable c = lock.write()) {
|
||||
invalid = true;
|
||||
acceptedSourceAssociations.clear();
|
||||
acceptedDestinationAssociations.clear();
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
void remove(Address sourceAddress, Address destinationAddress) {
|
||||
lock.acquire();
|
||||
try {
|
||||
try (Closeable c = lock.write()) {
|
||||
if (disposed || invalid) {
|
||||
return;
|
||||
}
|
||||
acceptedSourceAssociations.remove(sourceAddress);
|
||||
acceptedDestinationAssociations.remove(destinationAddress);
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
void add(Address sourceAddress, Address destinationAddress) {
|
||||
lock.acquire();
|
||||
try {
|
||||
try (Closeable c = lock.write()) {
|
||||
if (disposed || invalid) {
|
||||
return;
|
||||
}
|
||||
acceptedSourceAssociations.add(sourceAddress);
|
||||
acceptedDestinationAssociations.add(destinationAddress);
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
boolean isBlocked(Address sourceAddress, Address destinationAddress) {
|
||||
|
||||
lock.acquire();
|
||||
try {
|
||||
try (Closeable c = lock.read()) {
|
||||
|
||||
if (disposed) {
|
||||
return true;
|
||||
@@ -735,9 +642,6 @@ public class AssociationDatabaseManager implements VTAssociationManager {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -749,7 +653,7 @@ public class AssociationDatabaseManager implements VTAssociationManager {
|
||||
.getRelatedAssociationRecordsBySourceAndDestinationAddress(sourceID,
|
||||
destinationID);
|
||||
for (DBRecord record : relatedRecords) {
|
||||
VTAssociationDB associationDB = getAssociationForRecord(record);
|
||||
VTAssociationDB associationDB = associationCache.getCachedInstance(record);
|
||||
VTAssociationStatus status = associationDB.getStatus();
|
||||
if (status == ACCEPTED) {
|
||||
return true;
|
||||
@@ -785,7 +689,7 @@ public class AssociationDatabaseManager implements VTAssociationManager {
|
||||
while (it.hasNext()) {
|
||||
monitor.increment();
|
||||
DBRecord record = it.next();
|
||||
VTAssociationDB associationDB = getAssociationForRecord(record);
|
||||
VTAssociationDB associationDB = associationCache.getCachedInstance(record);
|
||||
VTAssociationStatus status = associationDB.getStatus();
|
||||
if (status == ACCEPTED) {
|
||||
Address sourceAddress = associationDB.getSourceAddress();
|
||||
@@ -804,4 +708,48 @@ public class AssociationDatabaseManager implements VTAssociationManager {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class AssociationFactory implements DbFactory<VTAssociationDB> {
|
||||
|
||||
@Override
|
||||
public VTAssociationDB instantiate(long key) {
|
||||
try {
|
||||
DBRecord record = associationTableAdapter.getRecord(key);
|
||||
return record == null ? null : instantiate(record);
|
||||
}
|
||||
catch (IOException e) {
|
||||
session.dbError(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public VTAssociationDB instantiate(DBRecord rec) {
|
||||
return new VTAssociationDB(AssociationDatabaseManager.this, rec);
|
||||
}
|
||||
}
|
||||
|
||||
private class MarkupFactory implements DbFactory<MarkupItemStorageDB> {
|
||||
|
||||
@Override
|
||||
public MarkupItemStorageDB instantiate(long key) {
|
||||
try {
|
||||
DBRecord record = markupItemTableAdapter.getRecord(key);
|
||||
return record == null ? null : instantiate(record);
|
||||
}
|
||||
catch (IOException e) {
|
||||
session.dbError(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public MarkupItemStorageDB instantiate(DBRecord rec) {
|
||||
return new MarkupItemStorageDB(rec, AssociationDatabaseManager.this);
|
||||
}
|
||||
}
|
||||
|
||||
VTAssociation getAssociation(long associationKey) {
|
||||
return associationCache.getCachedInstance(associationKey);
|
||||
}
|
||||
}
|
||||
|
||||
+46
-30
@@ -4,9 +4,9 @@
|
||||
* 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.
|
||||
@@ -25,22 +25,21 @@ import ghidra.feature.vt.api.main.VTMarkupItemStatus;
|
||||
import ghidra.feature.vt.api.markuptype.VTMarkupType;
|
||||
import ghidra.feature.vt.api.markuptype.VTMarkupTypeFactory;
|
||||
import ghidra.feature.vt.api.util.Stringable;
|
||||
import ghidra.program.database.DBObjectCache;
|
||||
import ghidra.program.database.DatabaseObject;
|
||||
import ghidra.program.database.DbObject;
|
||||
import ghidra.program.database.map.AddressMap;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.util.Lock.Closeable;
|
||||
|
||||
public class MarkupItemStorageDB extends DatabaseObject implements MarkupItemStorage {
|
||||
public class MarkupItemStorageDB extends DbObject implements MarkupItemStorage {
|
||||
private final AssociationDatabaseManager associationManager;
|
||||
private final VTAssociation association;
|
||||
private final VTSessionDB session;
|
||||
|
||||
private DBRecord record;
|
||||
|
||||
MarkupItemStorageDB(DBRecord record, DBObjectCache<MarkupItemStorageDB> cache,
|
||||
AssociationDatabaseManager associationManager) {
|
||||
super(cache, record.getKey());
|
||||
MarkupItemStorageDB(DBRecord record, AssociationDatabaseManager associationManager) {
|
||||
super(record.getKey());
|
||||
this.record = record;
|
||||
this.associationManager = associationManager;
|
||||
this.session = associationManager.getSession();
|
||||
@@ -60,47 +59,67 @@ public class MarkupItemStorageDB extends DatabaseObject implements MarkupItemSto
|
||||
|
||||
@Override
|
||||
public Address getSourceAddress() {
|
||||
long addressLong = record.getLongValue(SOURCE_ADDRESS_COL.column());
|
||||
Program program = session.getSourceProgram();
|
||||
AddressMap addressMap = program.getAddressMap();
|
||||
return addressMap.decodeAddress(addressLong);
|
||||
try (Closeable c = associationManager.lock.read()) {
|
||||
refreshIfNeeded();
|
||||
long addressLong = record.getLongValue(SOURCE_ADDRESS_COL.column());
|
||||
Program program = session.getSourceProgram();
|
||||
AddressMap addressMap = program.getAddressMap();
|
||||
return addressMap.decodeAddress(addressLong);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Address getDestinationAddress() {
|
||||
long addressLong = record.getLongValue(DESTINATION_ADDRESS_COL.column());
|
||||
Program program = session.getDestinationProgram();
|
||||
AddressMap addressMap = program.getAddressMap();
|
||||
return addressMap.decodeAddress(addressLong);
|
||||
try (Closeable c = associationManager.lock.read()) {
|
||||
refreshIfNeeded();
|
||||
long addressLong = record.getLongValue(DESTINATION_ADDRESS_COL.column());
|
||||
Program program = session.getDestinationProgram();
|
||||
AddressMap addressMap = program.getAddressMap();
|
||||
return addressMap.decodeAddress(addressLong);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDestinationAddressSource() {
|
||||
return record.getString(ADDRESS_SOURCE_COL.column());
|
||||
try (Closeable c = associationManager.lock.read()) {
|
||||
refreshIfNeeded();
|
||||
return record.getString(ADDRESS_SOURCE_COL.column());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public VTMarkupItemStatus getStatus() {
|
||||
checkIsValid();
|
||||
byte ordinal = record.getByteValue(STATUS_COL.column());
|
||||
return VTMarkupItemStatus.values()[ordinal];
|
||||
try (Closeable c = associationManager.lock.read()) {
|
||||
refreshIfNeeded();
|
||||
byte ordinal = record.getByteValue(STATUS_COL.column());
|
||||
return VTMarkupItemStatus.values()[ordinal];
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStatusDescription() {
|
||||
return record.getString(STATUS_DESCRIPTION_COL.column());
|
||||
try (Closeable c = associationManager.lock.read()) {
|
||||
refreshIfNeeded();
|
||||
return record.getString(STATUS_DESCRIPTION_COL.column());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stringable getSourceValue() {
|
||||
String string = record.getString(SOURCE_VALUE_COL.column());
|
||||
return Stringable.getStringable(string, session.getSourceProgram());
|
||||
try (Closeable c = associationManager.lock.read()) {
|
||||
refreshIfNeeded();
|
||||
String string = record.getString(SOURCE_VALUE_COL.column());
|
||||
return Stringable.getStringable(string, session.getSourceProgram());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stringable getDestinationValue() {
|
||||
String string = record.getString(ORIGINAL_DESTINATION_VALUE_COL.column());
|
||||
return Stringable.getStringable(string, session.getDestinationProgram());
|
||||
try (Closeable c = associationManager.lock.read()) {
|
||||
refreshIfNeeded();
|
||||
String string = record.getString(ORIGINAL_DESTINATION_VALUE_COL.column());
|
||||
return Stringable.getStringable(string, session.getDestinationProgram());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -131,16 +150,13 @@ public class MarkupItemStorageDB extends DatabaseObject implements MarkupItemSto
|
||||
|
||||
@Override
|
||||
public MarkupItemStorage reset() {
|
||||
associationManager.lock.acquire();
|
||||
try {
|
||||
try (Closeable c = associationManager.lock.write()) {
|
||||
checkDeleted();
|
||||
MarkupItemStorage storage = new MarkupItemStorageImpl(getAssociation(), getMarkupType(),
|
||||
getSourceAddress(), getDestinationAddress(), getDestinationAddressSource());
|
||||
associationManager.removeMarkupRecord(record.getKey());
|
||||
return storage;
|
||||
}
|
||||
finally {
|
||||
associationManager.lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+29
-65
@@ -4,9 +4,9 @@
|
||||
* 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.
|
||||
@@ -24,21 +24,25 @@ import ghidra.feature.vt.api.impl.MarkupItemManagerImpl;
|
||||
import ghidra.feature.vt.api.impl.VTEvent;
|
||||
import ghidra.feature.vt.api.main.*;
|
||||
import ghidra.feature.vt.api.util.VTAssociationStatusException;
|
||||
import ghidra.program.database.DBObjectCache;
|
||||
import ghidra.program.database.DatabaseObject;
|
||||
import ghidra.program.database.DbObject;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.util.Lock.Closeable;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
public class VTAssociationDB extends DatabaseObject implements VTAssociation {
|
||||
public class VTAssociationDB extends DbObject implements VTAssociation {
|
||||
|
||||
public DBRecord record;
|
||||
private MarkupItemManagerImpl markupManager;
|
||||
public final AssociationDatabaseManager associationDBM;
|
||||
|
||||
public VTAssociationDB(AssociationDatabaseManager associationManager,
|
||||
DBObjectCache<VTAssociationDB> cache, DBRecord record) {
|
||||
super(cache, record.getKey());
|
||||
/**
|
||||
* Constructor
|
||||
* @param associationManager the association database manager
|
||||
* @param record the record for the association
|
||||
*/
|
||||
VTAssociationDB(AssociationDatabaseManager associationManager, DBRecord record) {
|
||||
super(record.getKey());
|
||||
this.associationDBM = associationManager;
|
||||
this.record = record;
|
||||
markupManager = new MarkupItemManagerImpl(this);
|
||||
@@ -93,41 +97,29 @@ public class VTAssociationDB extends DatabaseObject implements VTAssociation {
|
||||
|
||||
@Override
|
||||
public Address getSourceAddress() {
|
||||
associationDBM.lock.acquire();
|
||||
try {
|
||||
checkIsValid();
|
||||
try (Closeable c = associationDBM.lock.read()) {
|
||||
refreshIfNeeded();
|
||||
return associationDBM
|
||||
.getSourceAddressFromLong(record.getLongValue(SOURCE_ADDRESS_COL.column()));
|
||||
}
|
||||
finally {
|
||||
associationDBM.lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Address getDestinationAddress() {
|
||||
associationDBM.lock.acquire();
|
||||
try {
|
||||
checkIsValid();
|
||||
try (Closeable c = associationDBM.lock.read()) {
|
||||
refreshIfNeeded();
|
||||
return associationDBM.getDestinationAddressFromLong(
|
||||
record.getLongValue(DESTINATION_ADDRESS_COL.column()));
|
||||
}
|
||||
finally {
|
||||
associationDBM.lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public VTAssociationType getType() {
|
||||
associationDBM.lock.acquire();
|
||||
try {
|
||||
checkIsValid();
|
||||
try (Closeable c = associationDBM.lock.read()) {
|
||||
refreshIfNeeded();
|
||||
byte associationTypeOrdinal = record.getByteValue(TYPE_COL.column());
|
||||
return VTAssociationType.values()[associationTypeOrdinal];
|
||||
}
|
||||
finally {
|
||||
associationDBM.lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
public void markupItemStatusChanged(VTMarkupItem markupItem) {
|
||||
@@ -136,37 +128,25 @@ public class VTAssociationDB extends DatabaseObject implements VTAssociation {
|
||||
|
||||
@Override
|
||||
public VTAssociationStatus getStatus() {
|
||||
associationDBM.lock.acquire();
|
||||
try {
|
||||
checkIsValid();
|
||||
try (Closeable c = associationDBM.lock.read()) {
|
||||
refreshIfNeeded();
|
||||
return VTAssociationStatus.values()[record.getByteValue(STATUS_COL.column())];
|
||||
}
|
||||
finally {
|
||||
associationDBM.lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public VTAssociationMarkupStatus getMarkupStatus() {
|
||||
associationDBM.lock.acquire();
|
||||
try {
|
||||
checkIsValid();
|
||||
try (Closeable c = associationDBM.lock.read()) {
|
||||
refreshIfNeeded();
|
||||
return new VTAssociationMarkupStatus(record.getByteValue(APPLIED_STATUS_COL.column()));
|
||||
}
|
||||
finally {
|
||||
associationDBM.lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
DBRecord getRecord() {
|
||||
associationDBM.lock.acquire();
|
||||
try {
|
||||
checkIsValid();
|
||||
try (Closeable c = associationDBM.lock.read()) {
|
||||
refreshIfNeeded();
|
||||
return record;
|
||||
}
|
||||
finally {
|
||||
associationDBM.lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -220,20 +200,15 @@ public class VTAssociationDB extends DatabaseObject implements VTAssociation {
|
||||
|
||||
@Override
|
||||
public int getVoteCount() {
|
||||
associationDBM.lock.acquire();
|
||||
try {
|
||||
checkIsValid();
|
||||
try (Closeable c = associationDBM.lock.read()) {
|
||||
refreshIfNeeded();
|
||||
return record.getIntValue(VOTE_COUNT_COL.column());
|
||||
}
|
||||
finally {
|
||||
associationDBM.lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMarkupStatus(VTAssociationMarkupStatus status) {
|
||||
associationDBM.lock.acquire();
|
||||
try {
|
||||
try (Closeable c = associationDBM.lock.write()) {
|
||||
checkDeleted();
|
||||
VTAssociationMarkupStatus existingStatus = getMarkupStatus();
|
||||
if (status.equals(existingStatus)) {
|
||||
@@ -246,14 +221,10 @@ public class VTAssociationDB extends DatabaseObject implements VTAssociation {
|
||||
.setObjectChanged(VTEvent.ASSOCIATION_MARKUP_STATUS_CHANGED, this,
|
||||
existingStatus, status);
|
||||
}
|
||||
finally {
|
||||
associationDBM.lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
public void setStatus(VTAssociationStatus status) {
|
||||
associationDBM.lock.acquire();
|
||||
try {
|
||||
try (Closeable c = associationDBM.lock.write()) {
|
||||
checkDeleted();
|
||||
VTAssociationStatus existingStatus = getStatus();
|
||||
if (status == existingStatus) {
|
||||
@@ -266,15 +237,11 @@ public class VTAssociationDB extends DatabaseObject implements VTAssociation {
|
||||
.setObjectChanged(VTEvent.ASSOCIATION_STATUS_CHANGED, this, existingStatus,
|
||||
status);
|
||||
}
|
||||
finally {
|
||||
associationDBM.lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVoteCount(int voteCount) {
|
||||
associationDBM.lock.acquire();
|
||||
try {
|
||||
try (Closeable c = associationDBM.lock.write()) {
|
||||
checkDeleted();
|
||||
voteCount = Math.max(0, voteCount);
|
||||
record.setIntValue(VOTE_COUNT_COL.column(), voteCount);
|
||||
@@ -282,9 +249,6 @@ public class VTAssociationDB extends DatabaseObject implements VTAssociation {
|
||||
associationDBM.getSession()
|
||||
.setObjectChanged(VTEvent.VOTE_COUNT_CHANGED, this, null, null);
|
||||
}
|
||||
finally {
|
||||
associationDBM.lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+10
-18
@@ -4,9 +4,9 @@
|
||||
* 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.
|
||||
@@ -23,14 +23,14 @@ import db.DBRecord;
|
||||
import ghidra.feature.vt.api.impl.VTEvent;
|
||||
import ghidra.feature.vt.api.impl.VTProgramCorrelatorInfo;
|
||||
import ghidra.feature.vt.api.main.*;
|
||||
import ghidra.program.database.DBObjectCache;
|
||||
import ghidra.program.database.DatabaseObject;
|
||||
import ghidra.program.database.DbObject;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.util.Lock;
|
||||
import ghidra.util.Lock.Closeable;
|
||||
import ghidra.util.SystemUtilities;
|
||||
import ghidra.util.exception.AssertException;
|
||||
|
||||
public class VTMatchDB extends DatabaseObject implements VTMatch {
|
||||
public class VTMatchDB extends DbObject implements VTMatch {
|
||||
|
||||
private DBRecord record;
|
||||
private final VTMatchSetDB matchSet;
|
||||
@@ -42,8 +42,8 @@ public class VTMatchDB extends DatabaseObject implements VTMatch {
|
||||
private boolean doCalculateHash = true;
|
||||
private int hash;
|
||||
|
||||
public VTMatchDB(DBObjectCache<VTMatchDB> cache, DBRecord record, VTMatchSetDB matchSet) {
|
||||
super(cache, record.getKey());
|
||||
public VTMatchDB(DBRecord record, VTMatchSetDB matchSet) {
|
||||
super(record.getKey());
|
||||
this.record = record;
|
||||
this.matchSet = matchSet;
|
||||
session = (VTSessionDB) matchSet.getSession();
|
||||
@@ -105,8 +105,7 @@ public class VTMatchDB extends DatabaseObject implements VTMatch {
|
||||
|
||||
@Override
|
||||
public void setTag(VTMatchTag tag) {
|
||||
lock.acquire();
|
||||
try {
|
||||
try (Closeable c = lock.write()) {
|
||||
checkDeleted();
|
||||
if (record == null) {
|
||||
return;
|
||||
@@ -127,9 +126,6 @@ public class VTMatchDB extends DatabaseObject implements VTMatch {
|
||||
updateRecord();
|
||||
session.setObjectChanged(VTEvent.MATCH_TAG_CHANGED, this, oldTag, newTagDB);
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
private VTAssociation loadAssociation() {
|
||||
@@ -145,16 +141,12 @@ public class VTMatchDB extends DatabaseObject implements VTMatch {
|
||||
|
||||
@Override
|
||||
public VTAssociation getAssociation() {
|
||||
lock.acquire();
|
||||
try {
|
||||
checkIsValid();
|
||||
try (Closeable c = lock.read()) {
|
||||
refreshIfNeeded();
|
||||
if (association == null) {
|
||||
association = loadAssociation();
|
||||
}
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
return association;
|
||||
}
|
||||
|
||||
|
||||
+54
-60
@@ -30,22 +30,22 @@ import ghidra.feature.vt.api.main.*;
|
||||
import ghidra.framework.data.OpenMode;
|
||||
import ghidra.framework.options.Options;
|
||||
import ghidra.framework.options.ToolOptions;
|
||||
import ghidra.program.database.DBObjectCache;
|
||||
import ghidra.program.database.DatabaseObject;
|
||||
import ghidra.program.database.*;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSet;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.util.Lock;
|
||||
import ghidra.util.Lock.Closeable;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.exception.VersionException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
import ghidra.util.xml.XmlUtilities;
|
||||
|
||||
public class VTMatchSetDB extends DatabaseObject implements VTMatchSet {
|
||||
public class VTMatchSetDB extends DbObject implements VTMatchSet {
|
||||
|
||||
private final DBRecord matchSetRecord;
|
||||
|
||||
private DBObjectCache<VTMatchDB> matchCache;
|
||||
private DbCache<VTMatchDB> matchCache;
|
||||
private final VTSessionDB session;
|
||||
private VTMatchTableDBAdapter matchTableAdapter;
|
||||
|
||||
@@ -73,13 +73,13 @@ public class VTMatchSetDB extends DatabaseObject implements VTMatchSet {
|
||||
}
|
||||
|
||||
private VTMatchSetDB(DBRecord record, VTSessionDB session, DBHandle dbHandle, Lock lock) {
|
||||
super(null, record.getKey());// cache not supported
|
||||
super(record.getKey());// cache not supported
|
||||
this.matchSetRecord = record;
|
||||
this.session = session;
|
||||
this.dbHandle = dbHandle;
|
||||
this.lock = lock;
|
||||
|
||||
matchCache = new DBObjectCache<>(10);
|
||||
matchCache = new DbCache<>(new MatchFactory(), lock, 10);
|
||||
}
|
||||
|
||||
private void createTableAdapters(long tableID) throws IOException {
|
||||
@@ -162,20 +162,17 @@ public class VTMatchSetDB extends DatabaseObject implements VTMatchSet {
|
||||
VTAssociationDB associationDB = associationManager.getOrCreateAssociationDB(
|
||||
info.getSourceAddress(), info.getDestinationAddress(), info.getAssociationType());
|
||||
VTMatchTag tag = info.getTag();
|
||||
VTMatch newMatch = null;
|
||||
try {
|
||||
lock.acquire();
|
||||
VTMatchDB newMatch = null;
|
||||
try (Closeable c = lock.write()) {
|
||||
VTMatchTagDB tagDB = session.getOrCreateMatchTagDB(tag);
|
||||
DBRecord matchRecord =
|
||||
matchTableAdapter.insertMatchRecord(info, this, associationDB, tagDB);
|
||||
newMatch = getMatchForRecord(matchRecord);
|
||||
newMatch = new VTMatchDB(matchRecord, this);
|
||||
matchCache.add(newMatch);
|
||||
}
|
||||
catch (IOException e) {
|
||||
dbError(e);
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
if (newMatch != null) {
|
||||
session.setObjectChanged(VTEvent.MATCH_ADDED, newMatch, null, newMatch);
|
||||
}
|
||||
@@ -213,8 +210,8 @@ public class VTMatchSetDB extends DatabaseObject implements VTMatchSet {
|
||||
VTAssociation association = match.getAssociation();
|
||||
Address sourceAddress = association.getSourceAddress();
|
||||
Address destinationAddress = association.getDestinationAddress();
|
||||
try {
|
||||
lock.acquire();
|
||||
try (Closeable c = lock.write()) {
|
||||
checkDeleted();
|
||||
long matchKey = matchDb.getKey();
|
||||
boolean deleted = matchTableAdapter.deleteRecord(matchKey);
|
||||
if (deleted) {
|
||||
@@ -231,9 +228,6 @@ public class VTMatchSetDB extends DatabaseObject implements VTMatchSet {
|
||||
catch (IOException e) {
|
||||
dbError(e);
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
|
||||
DeletedMatch deletedMatch = new DeletedMatch(sourceAddress, destinationAddress);
|
||||
session.setObjectChanged(VTEvent.MATCH_DELETED, match, deletedMatch, null);
|
||||
@@ -247,35 +241,31 @@ public class VTMatchSetDB extends DatabaseObject implements VTMatchSet {
|
||||
@Override
|
||||
public Collection<VTMatch> getMatches() {
|
||||
List<VTMatch> list = new LinkedList<>();
|
||||
try {
|
||||
lock.acquire();
|
||||
try (Closeable c = lock.read()) {
|
||||
RecordIterator iterator = matchTableAdapter.getRecords();
|
||||
while (iterator.hasNext()) {
|
||||
DBRecord nextRecord = iterator.next();
|
||||
list.add(getMatchForRecord(nextRecord));
|
||||
list.add(matchCache.getCachedInstance(nextRecord));
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
dbError(e);
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<VTMatch> getMatches(VTAssociation association) {
|
||||
VTAssociationDB associationDB = (VTAssociationDB) association;
|
||||
List<VTMatch> list = new LinkedList<>();
|
||||
if (associationDB == null) {
|
||||
return list; // No association, so no matches.
|
||||
}
|
||||
try {
|
||||
try (Closeable c = lock.read()) {
|
||||
VTAssociationDB associationDB = (VTAssociationDB) association;
|
||||
if (associationDB == null) {
|
||||
return list; // No association, so no matches.
|
||||
}
|
||||
RecordIterator iterator = matchTableAdapter.getRecords(associationDB.getKey());
|
||||
while (iterator.hasNext()) {
|
||||
DBRecord nextRecord = iterator.next();
|
||||
VTMatch match = getMatchForRecord(nextRecord);
|
||||
VTMatch match = matchCache.getCachedInstance(nextRecord);
|
||||
list.add(match);
|
||||
}
|
||||
}
|
||||
@@ -287,44 +277,23 @@ public class VTMatchSetDB extends DatabaseObject implements VTMatchSet {
|
||||
|
||||
@Override
|
||||
public Collection<VTMatch> getMatches(Address sourceAddress, Address destinationAddress) {
|
||||
AssociationDatabaseManager associationManager = session.getAssociationManagerDBM();
|
||||
VTAssociationDB existingAssociationDB =
|
||||
associationManager.getExistingAssociationDB(sourceAddress, destinationAddress);
|
||||
if (existingAssociationDB == null) {
|
||||
return Collections.emptyList();
|
||||
try (Closeable c = lock.read()) {
|
||||
AssociationDatabaseManager associationManager = session.getAssociationManagerDBM();
|
||||
VTAssociationDB existingAssociationDB =
|
||||
associationManager.getExistingAssociationDB(sourceAddress, destinationAddress);
|
||||
if (existingAssociationDB == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return getMatches(existingAssociationDB);
|
||||
}
|
||||
return getMatches(existingAssociationDB);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean refresh() {
|
||||
// MatchSets are not cached, so this method is not used
|
||||
return true;
|
||||
}
|
||||
|
||||
private VTMatch getMatchForRecord(DBRecord matchRecord) {
|
||||
try {
|
||||
lock.acquire();
|
||||
VTMatchDB match = matchCache.get(matchRecord);
|
||||
if (match == null) {
|
||||
match = new VTMatchDB(matchCache, matchRecord, this);
|
||||
}
|
||||
return match;
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
DBRecord getMatchRecord(long matchRecordKey) {
|
||||
try {
|
||||
return matchTableAdapter.getMatchRecord(matchRecordKey);
|
||||
}
|
||||
catch (IOException e) {
|
||||
dbError(e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Program getDestinationProgram() {
|
||||
return session.getDestinationProgram();
|
||||
}
|
||||
@@ -345,9 +314,34 @@ public class VTMatchSetDB extends DatabaseObject implements VTMatchSet {
|
||||
matchCache.invalidate();
|
||||
}
|
||||
|
||||
DBRecord getMatchRecord(long matchKey) {
|
||||
try {
|
||||
return matchTableAdapter.getMatchRecord(matchKey);
|
||||
}
|
||||
catch (IOException e) {
|
||||
session.dbError(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Match Set " + getID() + " - " + getMatchCount() + " matches [Correlator=" +
|
||||
getProgramCorrelatorInfo().getName() + "]";
|
||||
}
|
||||
|
||||
private class MatchFactory implements DbFactory<VTMatchDB> {
|
||||
|
||||
@Override
|
||||
public VTMatchDB instantiate(long matchKey) {
|
||||
DBRecord record = getMatchRecord(matchKey);
|
||||
return record == null ? null : instantiate(record);
|
||||
}
|
||||
|
||||
@Override
|
||||
public VTMatchDB instantiate(DBRecord rec) {
|
||||
return new VTMatchDB(rec, VTMatchSetDB.this);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+6
-7
@@ -15,25 +15,24 @@
|
||||
*/
|
||||
package ghidra.feature.vt.api.db;
|
||||
|
||||
import static ghidra.feature.vt.api.db.VTMatchTagDBAdapter.ColumnDescription.TAG_NAME_COL;
|
||||
import static ghidra.feature.vt.api.db.VTMatchTagDBAdapter.ColumnDescription.*;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import db.DBRecord;
|
||||
import ghidra.feature.vt.api.main.VTMatchTag;
|
||||
import ghidra.program.database.DBObjectCache;
|
||||
import ghidra.program.database.DatabaseObject;
|
||||
import ghidra.program.database.DbObject;
|
||||
|
||||
/**
|
||||
* The database object for a user defined tag on a version tracking match.
|
||||
*/
|
||||
public class VTMatchTagDB extends DatabaseObject implements VTMatchTag {
|
||||
public class VTMatchTagDB extends DbObject implements VTMatchTag {
|
||||
|
||||
private VTSessionDB sessionDB;
|
||||
private DBRecord record;
|
||||
|
||||
VTMatchTagDB(VTSessionDB sessionDB, DBObjectCache<VTMatchTagDB> cache, DBRecord record) {
|
||||
super(cache, record.getKey());
|
||||
VTMatchTagDB(VTSessionDB sessionDB, DBRecord record) {
|
||||
super(record.getKey());
|
||||
this.sessionDB = sessionDB;
|
||||
this.record = record;
|
||||
}
|
||||
@@ -75,7 +74,7 @@ public class VTMatchTagDB extends DatabaseObject implements VTMatchTag {
|
||||
* null if the match tag has been deleted.
|
||||
*/
|
||||
DBRecord getRecord() {
|
||||
return checkIsValid() ? record : null;
|
||||
return refreshIfNeeded() ? record : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+43
-86
@@ -32,12 +32,14 @@ import ghidra.framework.model.*;
|
||||
import ghidra.framework.model.TransactionInfo.Status;
|
||||
import ghidra.framework.options.Options;
|
||||
import ghidra.framework.store.LockException;
|
||||
import ghidra.program.database.DBObjectCache;
|
||||
import ghidra.program.database.DbCache;
|
||||
import ghidra.program.database.DbFactory;
|
||||
import ghidra.program.database.map.AddressMap;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSet;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.util.*;
|
||||
import ghidra.util.Lock.Closeable;
|
||||
import ghidra.util.exception.*;
|
||||
import ghidra.util.task.TaskLauncher;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
@@ -88,7 +90,7 @@ public class VTSessionDB extends DomainObjectAdapterDB implements VTSession {
|
||||
private VTMatchSetTableDBAdapter matchSetTableAdapter;
|
||||
private AssociationDatabaseManager associationManager;
|
||||
private VTMatchTagDBAdapter matchTagAdapter;
|
||||
private DBObjectCache<VTMatchTagDB> tagCache = new DBObjectCache<>(10);
|
||||
private DbCache<VTMatchTagDB> tagCache;
|
||||
|
||||
private Program sourceProgram;
|
||||
private Program destinationProgram;
|
||||
@@ -127,7 +129,7 @@ public class VTSessionDB extends DomainObjectAdapterDB implements VTSession {
|
||||
public VTSessionDB(String name, Program sourceProgram, Program destinationProgram,
|
||||
Object consumer) throws IOException {
|
||||
super(new DBHandle(), UNUSED_DEFAULT_NAME, EVENT_NOTIFICATION_DELAY, consumer);
|
||||
|
||||
tagCache = new DbCache<>(new TagFactory(), lock, 10);
|
||||
propertyTable = dbh.getTable(PROPERTY_TABLE_NAME);
|
||||
|
||||
int ID = startTransaction("Constructing New Version Tracking Match Set");
|
||||
@@ -435,16 +437,12 @@ public class VTSessionDB extends DomainObjectAdapterDB implements VTSession {
|
||||
|
||||
@Override
|
||||
protected void clearCache(boolean all) {
|
||||
lock.acquire();
|
||||
try {
|
||||
try (Closeable c = lock.write()) {
|
||||
super.clearCache(all);
|
||||
associationManager.invalidateCache();
|
||||
tagCache.invalidate();
|
||||
reconcileCachedMatchSets();
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -512,14 +510,10 @@ public class VTSessionDB extends DomainObjectAdapterDB implements VTSession {
|
||||
|
||||
@Override
|
||||
public VTMatchSet createMatchSet(VTProgramCorrelator correlator) {
|
||||
try {
|
||||
lock.acquire();
|
||||
try (Closeable c = lock.write()) {
|
||||
long id = matchSetTableAdapter.getNextMatchSetID();
|
||||
return createMatchSet(correlator, id);
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
private VTMatchSet createMatchSet(VTProgramCorrelator correlator, long id) {
|
||||
@@ -588,7 +582,7 @@ public class VTSessionDB extends DomainObjectAdapterDB implements VTSession {
|
||||
|
||||
@Override
|
||||
public List<VTMatchSet> getMatchSets() {
|
||||
return new ArrayList<>(matchSetMap.values());
|
||||
return lock.withRead(() -> new ArrayList<>(matchSetMap.values()));
|
||||
}
|
||||
|
||||
AddressSet getSourceAddressSet(DBRecord record) throws IOException {
|
||||
@@ -649,17 +643,13 @@ public class VTSessionDB extends DomainObjectAdapterDB implements VTSession {
|
||||
|
||||
@Override
|
||||
public List<VTMatch> getMatches(VTAssociation association) {
|
||||
try {
|
||||
lock.acquire();
|
||||
try (Closeable c = lock.read()) {
|
||||
List<VTMatch> matches = new ArrayList<>();
|
||||
for (VTMatchSet matchSet : matchSetMap.values()) {
|
||||
matches.addAll(matchSet.getMatches(association));
|
||||
}
|
||||
return matches;
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -679,30 +669,22 @@ public class VTSessionDB extends DomainObjectAdapterDB implements VTSession {
|
||||
|
||||
@Override
|
||||
public VTMatchSet getManualMatchSet() {
|
||||
try {
|
||||
lock.acquire();
|
||||
try (Closeable c = lock.read()) {
|
||||
if (manualMatchSet == null) {
|
||||
manualMatchSet = findMatchSet(ManualMatchProgramCorrelator.class.getName());
|
||||
}
|
||||
return manualMatchSet;
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public VTMatchSet getImpliedMatchSet() {
|
||||
try {
|
||||
lock.acquire();
|
||||
try (Closeable c = lock.read()) {
|
||||
if (impliedMatchSet == null) {
|
||||
impliedMatchSet = findMatchSet(ImpliedMatchProgramCorrelator.class.getName());
|
||||
}
|
||||
return impliedMatchSet;
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
private VTMatchSet findMatchSet(String correlatorClassName) {
|
||||
@@ -719,8 +701,7 @@ public class VTSessionDB extends DomainObjectAdapterDB implements VTSession {
|
||||
@Override
|
||||
public void deleteMatchTag(VTMatchTag tag) {
|
||||
String tagName = tag.getName();
|
||||
try {
|
||||
lock.acquire();
|
||||
try (Closeable c = lock.write()) {
|
||||
VTMatchTagDB tagDB = getMatchTagDB(tagName);
|
||||
if (tagDB == null) {
|
||||
return; // not sure if this can happen
|
||||
@@ -734,30 +715,24 @@ public class VTSessionDB extends DomainObjectAdapterDB implements VTSession {
|
||||
catch (IOException e) {
|
||||
dbError(e);
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
setObjectChanged(VTEvent.TAG_REMOVED, this, tagName, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public VTMatchTagDB createMatchTag(String tagName) {
|
||||
VTMatchTagDB matchTag = null;
|
||||
try {
|
||||
lock.acquire();
|
||||
try (Closeable c = lock.write()) {
|
||||
matchTag = getMatchTagDB(tagName);
|
||||
if (matchTag != null) {
|
||||
return matchTag;
|
||||
}
|
||||
DBRecord record = matchTagAdapter.insertRecord(tagName);
|
||||
matchTag = new VTMatchTagDB(this, tagCache, record);
|
||||
matchTag = new VTMatchTagDB(this, record);
|
||||
tagCache.add(matchTag);
|
||||
}
|
||||
catch (IOException e) {
|
||||
dbError(e);
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
setObjectChanged(VTEvent.TAG_ADDED, matchTag, null, matchTag);
|
||||
return matchTag;
|
||||
}
|
||||
@@ -773,66 +748,28 @@ public class VTSessionDB extends DomainObjectAdapterDB implements VTSession {
|
||||
return null;
|
||||
}
|
||||
|
||||
public VTMatchTag getMatchTag(long tagKey) {
|
||||
VTMatchTagDB tag = tagCache.getCachedInstance(tagKey);
|
||||
return tag != null ? tag : VTMatchTag.UNTAGGED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<VTMatchTag> getMatchTags() {
|
||||
Set<VTMatchTag> tags = new HashSet<>();
|
||||
try {
|
||||
lock.acquire();
|
||||
try (Closeable c = lock.read()) {
|
||||
RecordIterator records = matchTagAdapter.getRecords();
|
||||
while (records.hasNext()) {
|
||||
DBRecord record = records.next();
|
||||
tags.add(getMatchTagNew(record));
|
||||
tags.add(tagCache.getCachedInstance(record));
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
dbError(e);
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
|
||||
return tags;
|
||||
}
|
||||
|
||||
private VTMatchTagDB getMatchTagNew(DBRecord record) {
|
||||
if (record == null) {
|
||||
throw new AssertException("How can we have a null record?!!!");
|
||||
}
|
||||
|
||||
try {
|
||||
lock.acquire();
|
||||
VTMatchTagDB matchTagDB = tagCache.get(record);
|
||||
if (matchTagDB == null) {
|
||||
matchTagDB = new VTMatchTagDB(this, tagCache, record);
|
||||
}
|
||||
|
||||
return matchTagDB;
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
public VTMatchTag getMatchTag(long key) {
|
||||
try {
|
||||
lock.acquire();
|
||||
VTMatchTagDB matchTagDB = tagCache.get(key);
|
||||
if (matchTagDB != null) {
|
||||
return matchTagDB;
|
||||
}
|
||||
DBRecord record = matchTagAdapter.getRecord(key);
|
||||
if (record != null) {
|
||||
return new VTMatchTagDB(this, tagCache, record);
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
dbError(e);
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
return VTMatchTag.UNTAGGED;
|
||||
}
|
||||
|
||||
DBRecord getTagRecord(long key) throws IOException {
|
||||
return matchTagAdapter.getRecord(key);
|
||||
}
|
||||
@@ -875,4 +812,24 @@ public class VTSessionDB extends DomainObjectAdapterDB implements VTSession {
|
||||
associationManager.dispose();
|
||||
super.close();
|
||||
}
|
||||
|
||||
private class TagFactory implements DbFactory<VTMatchTagDB> {
|
||||
@Override
|
||||
public VTMatchTagDB instantiate(long key) {
|
||||
try {
|
||||
DBRecord record = matchTagAdapter.getRecord(key);
|
||||
return record == null ? null : instantiate(record);
|
||||
}
|
||||
catch (IOException e) {
|
||||
dbError(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public VTMatchTagDB instantiate(DBRecord record) {
|
||||
return new VTMatchTagDB(VTSessionDB.this, record);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-2
@@ -27,7 +27,7 @@ import ghidra.feature.vt.api.markuptype.*;
|
||||
import ghidra.feature.vt.api.util.Stringable;
|
||||
import ghidra.feature.vt.api.util.VersionTrackingApplyException;
|
||||
import ghidra.framework.options.ToolOptions;
|
||||
import ghidra.program.database.DatabaseObject;
|
||||
import ghidra.program.database.DbObject;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.util.ProgramLocation;
|
||||
import ghidra.util.SystemUtilities;
|
||||
@@ -402,7 +402,7 @@ public class MarkupItemImpl implements VTMarkupItem {
|
||||
}
|
||||
|
||||
public boolean isStoredInDB() {
|
||||
return (markupItemStorage instanceof DatabaseObject);
|
||||
return (markupItemStorage instanceof DbObject);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user