mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-06 03:50:02 +02:00
Merge remote-tracking branch 'origin/patch'
Conflicts: Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/cli/blobs/CliAbstractSig.java Ghidra/Framework/DB/src/main/java/db/DBHandle.java
This commit is contained in:
commit
066a7d0305
32 changed files with 920 additions and 129 deletions
|
@ -195,7 +195,7 @@ public class GhidraState {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the current selection and fire a {@link kProgramSelectionPluginEvent}.
|
* Set the current selection and fire a {@link ProgramSelectionPluginEvent}.
|
||||||
*
|
*
|
||||||
* @param selection the selection
|
* @param selection the selection
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -157,7 +157,7 @@ public interface ElfConstants {
|
||||||
|
|
||||||
/**No machine*/
|
/**No machine*/
|
||||||
public static final short EM_NONE = 0;
|
public static final short EM_NONE = 0;
|
||||||
/** AT&T WE 32100 */
|
/** AT&T WE 32100 */
|
||||||
public static final short EM_M32 = 1;
|
public static final short EM_M32 = 1;
|
||||||
/**SUN SPARC */
|
/**SUN SPARC */
|
||||||
public static final short EM_SPARC = 2;
|
public static final short EM_SPARC = 2;
|
||||||
|
|
|
@ -52,7 +52,7 @@ public abstract class AbstractDemangledFunctionDefinitionDataType extends Demang
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the string for this type of reference (e.g., * or &)
|
* Returns the string for this type of reference (e.g., * or &)
|
||||||
* @return the string
|
* @return the string
|
||||||
*/
|
*/
|
||||||
abstract protected String getTypeString();
|
abstract protected String getTypeString();
|
||||||
|
|
|
@ -187,12 +187,12 @@ public class Pattern extends DittedBitSequence {
|
||||||
/**
|
/**
|
||||||
* Read just the post patterns from the <patternpair> tags
|
* Read just the post patterns from the <patternpair> tags
|
||||||
* @param file is the file to read from
|
* @param file is the file to read from
|
||||||
* @param patternlist collects the resulting Pattern objects
|
* @param patternList collects the resulting Pattern objects
|
||||||
* @param pfactory is the factory for constructing postrules and matchactions
|
* @param pfactory is the factory for constructing postrules and matchactions
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
* @throws SAXException
|
* @throws SAXException
|
||||||
*/
|
*/
|
||||||
public static void readPostPatterns(File file, ArrayList<Pattern> patlist,
|
public static void readPostPatterns(File file, ArrayList<Pattern> patternList,
|
||||||
PatternFactory pfactory) throws SAXException, IOException {
|
PatternFactory pfactory) throws SAXException, IOException {
|
||||||
ErrorHandler handler = new ErrorHandler() {
|
ErrorHandler handler = new ErrorHandler() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -217,7 +217,7 @@ public class Pattern extends DittedBitSequence {
|
||||||
if (el.getName().equals("patternpairs")) {
|
if (el.getName().equals("patternpairs")) {
|
||||||
PatternPairSet pairset = new PatternPairSet();
|
PatternPairSet pairset = new PatternPairSet();
|
||||||
pairset.restoreXml(parser, pfactory);
|
pairset.restoreXml(parser, pfactory);
|
||||||
pairset.extractPostPatterns(patlist);
|
pairset.extractPostPatterns(patternList);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
parser.next();
|
parser.next();
|
||||||
|
|
|
@ -87,30 +87,31 @@ public class WrappedMemoryBufferTest extends AbstractGhidraHeadedIntegrationTest
|
||||||
|
|
||||||
Address minAddr = program.getMinAddress();
|
Address minAddr = program.getMinAddress();
|
||||||
Address maxAddr = program.getMaxAddress();
|
Address maxAddr = program.getMaxAddress();
|
||||||
setBytes(minAddr, new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 });
|
setBytes(minAddr,
|
||||||
|
new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 });
|
||||||
|
|
||||||
memBuf = new MemoryBufferImpl(program.getMemory(), minAddr);
|
memBuf = new MemoryBufferImpl(program.getMemory(), minAddr);
|
||||||
memBuf = new WrappedMemBuffer(memBuf, 4, 0);
|
memBuf = new WrappedMemBuffer(memBuf, 4, 0);
|
||||||
byte[] bytes = new byte[6];
|
byte[] bytes = new byte[6];
|
||||||
// test get too many for cache
|
// test get too many for cache
|
||||||
assertEquals(6, memBuf.getBytes(bytes, 2));
|
assertEquals(6, memBuf.getBytes(bytes, 2));
|
||||||
Assert.assertArrayEquals("Unexpected bytes read from memBuf", new byte[] { 2, 3, 4, 5, 6, 7 },
|
Assert.assertArrayEquals("Unexpected bytes read from memBuf",
|
||||||
bytes);
|
new byte[] { 2, 3, 4, 5, 6, 7 }, bytes);
|
||||||
|
|
||||||
// test not in buffer
|
// test not in buffer
|
||||||
memBuf = new WrappedMemBuffer(memBuf, 6, 0);
|
memBuf = new WrappedMemBuffer(memBuf, 6, 0);
|
||||||
assertEquals(6, memBuf.getBytes(bytes, 0));
|
assertEquals(6, memBuf.getBytes(bytes, 0));
|
||||||
Assert.assertArrayEquals("Unexpected bytes read from memBuf", new byte[] { 0, 1, 2, 3, 4, 5 },
|
Assert.assertArrayEquals("Unexpected bytes read from memBuf",
|
||||||
bytes);
|
new byte[] { 0, 1, 2, 3, 4, 5 }, bytes);
|
||||||
assertEquals(6, memBuf.getBytes(bytes, 2));
|
assertEquals(6, memBuf.getBytes(bytes, 2));
|
||||||
Assert.assertArrayEquals("Unexpected bytes read from memBuf", new byte[] { 2, 3, 4, 5, 6, 7 },
|
Assert.assertArrayEquals("Unexpected bytes read from memBuf",
|
||||||
bytes);
|
new byte[] { 2, 3, 4, 5, 6, 7 }, bytes);
|
||||||
assertEquals(6, memBuf.getBytes(bytes, 8));
|
assertEquals(6, memBuf.getBytes(bytes, 8));
|
||||||
Assert.assertArrayEquals("Unexpected bytes read from memBuf", new byte[] { 8, 9, 10, 11, 12, 13 },
|
Assert.assertArrayEquals("Unexpected bytes read from memBuf",
|
||||||
bytes);
|
new byte[] { 8, 9, 10, 11, 12, 13 }, bytes);
|
||||||
assertEquals(6, memBuf.getBytes(bytes, 1));
|
assertEquals(6, memBuf.getBytes(bytes, 1));
|
||||||
Assert.assertArrayEquals("Unexpected bytes read from memBuf", new byte[] { 1, 2, 3, 4, 5, 6 },
|
Assert.assertArrayEquals("Unexpected bytes read from memBuf",
|
||||||
bytes);
|
new byte[] { 1, 2, 3, 4, 5, 6 }, bytes);
|
||||||
|
|
||||||
assertEquals(10, memBuf.getByte(10));
|
assertEquals(10, memBuf.getByte(10));
|
||||||
assertEquals(0, memBuf.getByte(0));
|
assertEquals(0, memBuf.getByte(0));
|
||||||
|
@ -124,30 +125,31 @@ public class WrappedMemoryBufferTest extends AbstractGhidraHeadedIntegrationTest
|
||||||
|
|
||||||
Address minAddr = program.getMinAddress();
|
Address minAddr = program.getMinAddress();
|
||||||
Address maxAddr = program.getMaxAddress();
|
Address maxAddr = program.getMaxAddress();
|
||||||
setBytes(minAddr, new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 });
|
setBytes(minAddr,
|
||||||
|
new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 });
|
||||||
|
|
||||||
memBuf = new MemoryBufferImpl(program.getMemory(), minAddr);
|
memBuf = new MemoryBufferImpl(program.getMemory(), minAddr);
|
||||||
memBuf = new WrappedMemBuffer(memBuf, 0, 0);
|
memBuf = new WrappedMemBuffer(memBuf, 0, 0);
|
||||||
byte[] bytes = new byte[6];
|
byte[] bytes = new byte[6];
|
||||||
// test get too many for cache
|
// test get too many for cache
|
||||||
assertEquals(6, memBuf.getBytes(bytes, 2));
|
assertEquals(6, memBuf.getBytes(bytes, 2));
|
||||||
Assert.assertArrayEquals("Unexpected bytes read from memBuf", new byte[] { 2, 3, 4, 5, 6, 7 },
|
Assert.assertArrayEquals("Unexpected bytes read from memBuf",
|
||||||
bytes);
|
new byte[] { 2, 3, 4, 5, 6, 7 }, bytes);
|
||||||
|
|
||||||
// test not in buffer
|
// test not in buffer
|
||||||
memBuf = new WrappedMemBuffer(memBuf, 0, 0);
|
memBuf = new WrappedMemBuffer(memBuf, 0, 0);
|
||||||
assertEquals(6, memBuf.getBytes(bytes, 0));
|
assertEquals(6, memBuf.getBytes(bytes, 0));
|
||||||
Assert.assertArrayEquals("Unexpected bytes read from memBuf", new byte[] { 0, 1, 2, 3, 4, 5 },
|
Assert.assertArrayEquals("Unexpected bytes read from memBuf",
|
||||||
bytes);
|
new byte[] { 0, 1, 2, 3, 4, 5 }, bytes);
|
||||||
assertEquals(6, memBuf.getBytes(bytes, 2));
|
assertEquals(6, memBuf.getBytes(bytes, 2));
|
||||||
Assert.assertArrayEquals("Unexpected bytes read from memBuf", new byte[] { 2, 3, 4, 5, 6, 7 },
|
Assert.assertArrayEquals("Unexpected bytes read from memBuf",
|
||||||
bytes);
|
new byte[] { 2, 3, 4, 5, 6, 7 }, bytes);
|
||||||
assertEquals(6, memBuf.getBytes(bytes, 8));
|
assertEquals(6, memBuf.getBytes(bytes, 8));
|
||||||
Assert.assertArrayEquals("Unexpected bytes read from memBuf", new byte[] { 8, 9, 10, 11, 12, 13 },
|
Assert.assertArrayEquals("Unexpected bytes read from memBuf",
|
||||||
bytes);
|
new byte[] { 8, 9, 10, 11, 12, 13 }, bytes);
|
||||||
assertEquals(6, memBuf.getBytes(bytes, 1));
|
assertEquals(6, memBuf.getBytes(bytes, 1));
|
||||||
Assert.assertArrayEquals("Unexpected bytes read from memBuf", new byte[] { 1, 2, 3, 4, 5, 6 },
|
Assert.assertArrayEquals("Unexpected bytes read from memBuf",
|
||||||
bytes);
|
new byte[] { 1, 2, 3, 4, 5, 6 }, bytes);
|
||||||
|
|
||||||
assertEquals(10, memBuf.getByte(10));
|
assertEquals(10, memBuf.getByte(10));
|
||||||
assertEquals(0, memBuf.getByte(0));
|
assertEquals(0, memBuf.getByte(0));
|
||||||
|
@ -155,6 +157,151 @@ public class WrappedMemoryBufferTest extends AbstractGhidraHeadedIntegrationTest
|
||||||
assertEquals(6, memBuf.getByte(6));
|
assertEquals(6, memBuf.getByte(6));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetIntBuffered() throws Exception {
|
||||||
|
loadProgram("notepad");
|
||||||
|
int value;
|
||||||
|
|
||||||
|
Address minAddr = program.getMinAddress();
|
||||||
|
Address maxAddr = program.getMaxAddress();
|
||||||
|
setBytes(minAddr, new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
|
||||||
|
18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32 });
|
||||||
|
|
||||||
|
memBuf = new DumbMemBufferImpl(program.getMemory(), minAddr);
|
||||||
|
memBuf = new WrappedMemBuffer(memBuf, 3, 0);
|
||||||
|
|
||||||
|
value = memBuf.getInt(0);
|
||||||
|
assertEquals(value, 0x00010203);
|
||||||
|
value = memBuf.getInt(1);
|
||||||
|
assertEquals(value, 0x01020304);
|
||||||
|
value = memBuf.getInt(3);
|
||||||
|
assertEquals(value, 0x03040506);
|
||||||
|
value = memBuf.getInt(8);
|
||||||
|
assertEquals(value, 0x08090A0B);
|
||||||
|
|
||||||
|
memBuf = new DumbMemBufferImpl(program.getMemory(), minAddr);
|
||||||
|
memBuf = new WrappedMemBuffer(memBuf, 4, 0);
|
||||||
|
value = memBuf.getInt(0);
|
||||||
|
assertEquals(value, 0x00010203);
|
||||||
|
value = memBuf.getInt(1);
|
||||||
|
assertEquals(value, 0x01020304);
|
||||||
|
value = memBuf.getInt(3);
|
||||||
|
assertEquals(value, 0x03040506);
|
||||||
|
value = memBuf.getInt(8);
|
||||||
|
assertEquals(value, 0x08090A0B);
|
||||||
|
|
||||||
|
memBuf = new DumbMemBufferImpl(program.getMemory(), minAddr);
|
||||||
|
memBuf = new WrappedMemBuffer(memBuf, 5, 0);
|
||||||
|
value = memBuf.getInt(0);
|
||||||
|
assertEquals(value, 0x00010203);
|
||||||
|
value = memBuf.getInt(1);
|
||||||
|
assertEquals(value, 0x01020304);
|
||||||
|
value = memBuf.getInt(3);
|
||||||
|
assertEquals(value, 0x03040506);
|
||||||
|
value = memBuf.getInt(8);
|
||||||
|
assertEquals(value, 0x08090A0B);
|
||||||
|
|
||||||
|
memBuf = new MemoryBufferImpl(program.getMemory(), minAddr);
|
||||||
|
memBuf = new WrappedMemBuffer(memBuf, 3, 4);
|
||||||
|
value = memBuf.getInt(0);
|
||||||
|
assertEquals(value, 0x04050607);
|
||||||
|
value = memBuf.getInt(1);
|
||||||
|
assertEquals(value, 0x05060708);
|
||||||
|
value = memBuf.getInt(3);
|
||||||
|
assertEquals(value, 0x0708090A);
|
||||||
|
value = memBuf.getInt(8);
|
||||||
|
assertEquals(value, 0x0C0D0E0F);
|
||||||
|
|
||||||
|
memBuf = new MemoryBufferImpl(program.getMemory(), minAddr);
|
||||||
|
memBuf = new WrappedMemBuffer(memBuf, 4, 4);
|
||||||
|
value = memBuf.getInt(0);
|
||||||
|
assertEquals(value, 0x04050607);
|
||||||
|
value = memBuf.getInt(1);
|
||||||
|
assertEquals(value, 0x05060708);
|
||||||
|
value = memBuf.getInt(3);
|
||||||
|
assertEquals(value, 0x0708090A);
|
||||||
|
value = memBuf.getInt(8);
|
||||||
|
assertEquals(value, 0x0C0D0E0F);
|
||||||
|
|
||||||
|
memBuf = new DumbMemBufferImpl(program.getMemory(), minAddr);
|
||||||
|
memBuf = new WrappedMemBuffer(memBuf, 5, 4);
|
||||||
|
value = memBuf.getInt(0);
|
||||||
|
assertEquals(value, 0x04050607);
|
||||||
|
value = memBuf.getInt(1);
|
||||||
|
assertEquals(value, 0x05060708);
|
||||||
|
value = memBuf.getInt(3);
|
||||||
|
assertEquals(value, 0x0708090A);
|
||||||
|
value = memBuf.getInt(8);
|
||||||
|
assertEquals(value, 0x0C0D0E0F);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetShortBuffered() throws Exception {
|
||||||
|
loadProgram("notepad");
|
||||||
|
int value;
|
||||||
|
|
||||||
|
Address minAddr = program.getMinAddress();
|
||||||
|
Address maxAddr = program.getMaxAddress();
|
||||||
|
setBytes(minAddr, new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
|
||||||
|
18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32 });
|
||||||
|
|
||||||
|
memBuf = new DumbMemBufferImpl(program.getMemory(), minAddr);
|
||||||
|
memBuf = new WrappedMemBuffer(memBuf, 3, 0);
|
||||||
|
|
||||||
|
value = memBuf.getShort(0);
|
||||||
|
assertEquals(value, 0x0001);
|
||||||
|
value = memBuf.getShort(1);
|
||||||
|
assertEquals(value, 0x0102);
|
||||||
|
value = memBuf.getShort(3);
|
||||||
|
assertEquals(value, 0x0304);
|
||||||
|
value = memBuf.getShort(8);
|
||||||
|
assertEquals(value, 0x0809);
|
||||||
|
|
||||||
|
memBuf = new DumbMemBufferImpl(program.getMemory(), minAddr);
|
||||||
|
memBuf = new WrappedMemBuffer(memBuf, 5, 4);
|
||||||
|
value = memBuf.getShort(0);
|
||||||
|
assertEquals(value, 0x0405);
|
||||||
|
value = memBuf.getShort(1);
|
||||||
|
assertEquals(value, 0x0506);
|
||||||
|
value = memBuf.getShort(3);
|
||||||
|
assertEquals(value, 0x0708);
|
||||||
|
value = memBuf.getShort(8);
|
||||||
|
assertEquals(value, 0x0C0D);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetLongBuffered() throws Exception {
|
||||||
|
loadProgram("notepad");
|
||||||
|
long value;
|
||||||
|
|
||||||
|
Address minAddr = program.getMinAddress();
|
||||||
|
Address maxAddr = program.getMaxAddress();
|
||||||
|
setBytes(minAddr, new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 });
|
||||||
|
|
||||||
|
memBuf = new DumbMemBufferImpl(program.getMemory(), minAddr);
|
||||||
|
memBuf = new WrappedMemBuffer(memBuf, 7, 0);
|
||||||
|
|
||||||
|
value = memBuf.getLong(0);
|
||||||
|
assertEquals(value, 0x0001020304050607L);
|
||||||
|
value = memBuf.getLong(1);
|
||||||
|
assertEquals(value, 0x0102030405060708L);
|
||||||
|
value = memBuf.getLong(3);
|
||||||
|
assertEquals(value, 0x030405060708090AL);
|
||||||
|
value = memBuf.getLong(8);
|
||||||
|
assertEquals(value, 0x08090A0B0C0D0E0FL);
|
||||||
|
|
||||||
|
memBuf = new DumbMemBufferImpl(program.getMemory(), minAddr);
|
||||||
|
memBuf = new WrappedMemBuffer(memBuf, 9, 4);
|
||||||
|
value = memBuf.getLong(0);
|
||||||
|
assertEquals(value, 0x0405060708090A0BL);
|
||||||
|
value = memBuf.getLong(1);
|
||||||
|
assertEquals(value, 0x05060708090A0B0CL);
|
||||||
|
value = memBuf.getLong(3);
|
||||||
|
assertEquals(value, 0x0708090A0B0C0D0EL);
|
||||||
|
value = memBuf.getLong(0);
|
||||||
|
assertEquals(value, 0x0405060708090A0BL);
|
||||||
|
}
|
||||||
|
|
||||||
private void setBytes(Address addr, byte[] bytes) throws MemoryAccessException {
|
private void setBytes(Address addr, byte[] bytes) throws MemoryAccessException {
|
||||||
|
|
||||||
Memory mem = program.getMemory();
|
Memory mem = program.getMemory();
|
||||||
|
|
|
@ -194,6 +194,7 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
||||||
Dimension sd = satelliteViewer.getSize();
|
Dimension sd = satelliteViewer.getSize();
|
||||||
java.awt.Point p = new java.awt.Point(vvd.width - sd.width, vvd.height - sd.height);
|
java.awt.Point p = new java.awt.Point(vvd.width - sd.width, vvd.height - sd.height);
|
||||||
satelliteViewer.getComponent().setBounds(p.x, p.y, sd.width, sd.height);
|
satelliteViewer.getComponent().setBounds(p.x, p.y, sd.width, sd.height);
|
||||||
|
satelliteViewer.scaleToLayout();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -305,7 +306,7 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
||||||
new ActionBuilder("Reset View", ACTION_OWNER)
|
new ActionBuilder("Reset View", ACTION_OWNER)
|
||||||
.description("Fit Graph to Window")
|
.description("Fit Graph to Window")
|
||||||
.toolBarIcon(DefaultDisplayGraphIcons.FIT_TO_WINDOW)
|
.toolBarIcon(DefaultDisplayGraphIcons.FIT_TO_WINDOW)
|
||||||
.onAction(context -> viewer.scaleToLayout())
|
.onAction(context -> centerAndScale())
|
||||||
.buildAndInstallLocal(componentProvider);
|
.buildAndInstallLocal(componentProvider);
|
||||||
|
|
||||||
// create a button to show the view magnify lens
|
// create a button to show the view magnify lens
|
||||||
|
@ -641,6 +642,7 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
||||||
graphDisplayProvider.setDefaultSatelliteState(selected);
|
graphDisplayProvider.setDefaultSatelliteState(selected);
|
||||||
if (selected) {
|
if (selected) {
|
||||||
viewer.getComponent().add(satelliteViewer.getComponent());
|
viewer.getComponent().add(satelliteViewer.getComponent());
|
||||||
|
satelliteViewer.scaleToLayout();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
viewer.getComponent().remove(satelliteViewer.getComponent());
|
viewer.getComponent().remove(satelliteViewer.getComponent());
|
||||||
|
@ -827,6 +829,7 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
||||||
configureFilters();
|
configureFilters();
|
||||||
LayoutAlgorithm<AttributedVertex> initialLayoutAlgorithm =
|
LayoutAlgorithm<AttributedVertex> initialLayoutAlgorithm =
|
||||||
layoutTransitionManager.getInitialLayoutAlgorithm();
|
layoutTransitionManager.getInitialLayoutAlgorithm();
|
||||||
|
initialLayoutAlgorithm.setAfter(() -> centerAndScale());
|
||||||
viewer.getVisualizationModel().setLayoutAlgorithm(initialLayoutAlgorithm);
|
viewer.getVisualizationModel().setLayoutAlgorithm(initialLayoutAlgorithm);
|
||||||
});
|
});
|
||||||
componentProvider.setVisible(true);
|
componentProvider.setVisible(true);
|
||||||
|
@ -979,6 +982,7 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
||||||
*/
|
*/
|
||||||
public void centerAndScale() {
|
public void centerAndScale() {
|
||||||
viewer.scaleToLayout();
|
viewer.scaleToLayout();
|
||||||
|
satelliteViewer.scaleToLayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1080,7 +1084,7 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
||||||
public void ancestorAdded(AncestorEvent ancestorEvent) {
|
public void ancestorAdded(AncestorEvent ancestorEvent) {
|
||||||
vv.getComponent().removeAncestorListener(this);
|
vv.getComponent().removeAncestorListener(this);
|
||||||
Swing.runLater(() -> {
|
Swing.runLater(() -> {
|
||||||
vv.scaleToLayout();
|
centerAndScale();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -530,6 +530,25 @@ public class TypeParser {
|
||||||
type = new UserDefinedTypeModuleSourceAndLineMsType(pdb, reader);
|
type = new UserDefinedTypeModuleSourceAndLineMsType(pdb, reader);
|
||||||
//TODO: more work
|
//TODO: more work
|
||||||
break;
|
break;
|
||||||
|
case Class19MsType.PDB_ID:
|
||||||
|
type = new Class19MsType(pdb, reader);
|
||||||
|
break;
|
||||||
|
case Structure19MsType.PDB_ID:
|
||||||
|
type = new Structure19MsType(pdb, reader);
|
||||||
|
break;
|
||||||
|
// TODO: the following three types are only hypothetical and might be in the wrong
|
||||||
|
// order with the wrong PDB_IDs and the wrong internal elements and parsing.
|
||||||
|
// These are here as partial implementations until they are seen and can be
|
||||||
|
// cleaned up and put into service.
|
||||||
|
// case Union19MsType.PDB_ID:
|
||||||
|
// type = new Union19MsType(pdb, reader);
|
||||||
|
// break;
|
||||||
|
// case Enum19MsType.PDB_ID:
|
||||||
|
// type = new Enum19MsType(pdb, reader);
|
||||||
|
// break;
|
||||||
|
// case Interface19MsType.PDB_ID:
|
||||||
|
// type = new Interface19MsType(pdb, reader);
|
||||||
|
// break;
|
||||||
default:
|
default:
|
||||||
// This should never happen (unless we missed something
|
// This should never happen (unless we missed something
|
||||||
// or MSFT has added new in a version we do not handle.
|
// or MSFT has added new in a version we do not handle.
|
||||||
|
|
|
@ -26,8 +26,9 @@ import mdemangler.MDMang;
|
||||||
* Enums.
|
* Enums.
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractComplexMsType extends AbstractMsType {
|
public abstract class AbstractComplexMsType extends AbstractMsType {
|
||||||
|
// -1 is a flag to prevent the count from being emitted, which is what is desired if there
|
||||||
protected int count;
|
// is not a count field for the child type. 0 and up are valid values.
|
||||||
|
protected int count = -1;
|
||||||
protected RecordNumber fieldDescriptorListRecordNumber;
|
protected RecordNumber fieldDescriptorListRecordNumber;
|
||||||
protected MsProperty property;
|
protected MsProperty property;
|
||||||
protected String name;
|
protected String name;
|
||||||
|
|
|
@ -110,8 +110,10 @@ public abstract class AbstractCompositeMsType extends AbstractComplexMsType {
|
||||||
myBuilder.append(" ");
|
myBuilder.append(" ");
|
||||||
myBuilder.append(name);
|
myBuilder.append(name);
|
||||||
myBuilder.append("<");
|
myBuilder.append("<");
|
||||||
myBuilder.append(count);
|
if (count != -1) {
|
||||||
myBuilder.append(",");
|
myBuilder.append(count);
|
||||||
|
myBuilder.append(",");
|
||||||
|
}
|
||||||
myBuilder.append(property);
|
myBuilder.append(property);
|
||||||
myBuilder.append(">");
|
myBuilder.append(">");
|
||||||
AbstractMsType fieldType = getFieldDescriptorListType();
|
AbstractMsType fieldType = getFieldDescriptorListType();
|
||||||
|
|
|
@ -72,8 +72,10 @@ public abstract class AbstractEnumMsType extends AbstractComplexMsType {
|
||||||
myBuilder.append(" ");
|
myBuilder.append(" ");
|
||||||
myBuilder.append(name);
|
myBuilder.append(name);
|
||||||
myBuilder.append("<");
|
myBuilder.append("<");
|
||||||
myBuilder.append(count);
|
if (count != -1) {
|
||||||
myBuilder.append(",");
|
myBuilder.append(count);
|
||||||
|
myBuilder.append(",");
|
||||||
|
}
|
||||||
myBuilder.append(pdb.getTypeRecord(underlyingRecordNumber));
|
myBuilder.append(pdb.getTypeRecord(underlyingRecordNumber));
|
||||||
myBuilder.append(",");
|
myBuilder.append(",");
|
||||||
myBuilder.append(property);
|
myBuilder.append(property);
|
||||||
|
|
|
@ -0,0 +1,82 @@
|
||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.app.util.bin.format.pdb2.pdbreader.type;
|
||||||
|
|
||||||
|
import ghidra.app.util.bin.format.pdb2.pdbreader.*;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO this record type is a guess, using only data (no documentation) in its crafting.
|
||||||
|
* Thus, it can be cleaned up using trusted, msft-originated documentation if it becomes
|
||||||
|
* available and/or using more data analysis and/or non-trusted documentation.
|
||||||
|
* We are fairly certain that 0x1608 is some sort of class, but it could be a typedef class.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* This class represents the VS19 <B>MsType</B> flavor of C++ Class type. (At this time,
|
||||||
|
* PDB_ID is guessed to be a class similar to {@link ClassMsType}, eliminating
|
||||||
|
* the redundant count field, and adding other unknown field parsing.)
|
||||||
|
* <P>
|
||||||
|
* Note that class, struct, and interface are very closed related and have many of the same
|
||||||
|
* constructs and parsing procedures. However, they are separate. If any of the internals
|
||||||
|
* of one of these is changed, it is highly suggested that the others be changed as well as
|
||||||
|
* there is not code-shared between these other than by code duplication.
|
||||||
|
* <P>
|
||||||
|
* Note: we do not necessarily understand each of these data type classes. Refer to the
|
||||||
|
* base class for more information.
|
||||||
|
*/
|
||||||
|
public class Class19MsType extends AbstractClassMsType {
|
||||||
|
|
||||||
|
public static final int PDB_ID = 0x1608;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for this type.
|
||||||
|
* @param pdb {@link AbstractPdb} to which this type belongs.
|
||||||
|
* @param reader {@link PdbByteReader} from which this type is deserialized.
|
||||||
|
* @throws PdbException upon error parsing a field.
|
||||||
|
*/
|
||||||
|
public Class19MsType(AbstractPdb pdb, PdbByteReader reader) throws PdbException {
|
||||||
|
super(pdb, reader);
|
||||||
|
property = new MsProperty(reader);
|
||||||
|
int x = reader.parseUnsignedShortVal(); //unknown
|
||||||
|
fieldDescriptorListRecordNumber = RecordNumber.parse(pdb, reader, RecordCategory.TYPE, 32);
|
||||||
|
derivedFromListRecordNumber = RecordNumber.parse(pdb, reader, RecordCategory.TYPE, 32);
|
||||||
|
vShapeTableRecordNumber = RecordNumber.parse(pdb, reader, RecordCategory.TYPE, 32);
|
||||||
|
//TODO: has more... guessing below... commented out some other conditions, but we
|
||||||
|
// might want to investigate if any data hits them.
|
||||||
|
Numeric numericUnknown = new Numeric(reader); //unknown. Might even be just a short.
|
||||||
|
Numeric numeric = new Numeric(reader);
|
||||||
|
if (!numeric.isIntegral()) {
|
||||||
|
throw new PdbException("Expecting integral numeric");
|
||||||
|
}
|
||||||
|
size = numeric.getIntegral();
|
||||||
|
if (reader.hasMoreNonPad()) {
|
||||||
|
name = reader.parseString(pdb, StringParseType.StringNt);
|
||||||
|
if (reader.hasMoreNonPad()) {
|
||||||
|
mangledName = reader.parseString(pdb, StringParseType.StringNt);
|
||||||
|
}
|
||||||
|
// else if (reader.hasMore()) {
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
// else {
|
||||||
|
// }
|
||||||
|
reader.skipPadding();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getPdbId() {
|
||||||
|
return PDB_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,83 @@
|
||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.app.util.bin.format.pdb2.pdbreader.type;
|
||||||
|
|
||||||
|
import ghidra.app.util.bin.format.pdb2.pdbreader.*;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO this record type is a guess, using only data (no documentation) in its crafting.
|
||||||
|
* Thus, it can be cleaned up using trusted, msft-originated documentation if it becomes
|
||||||
|
* available and/or using more data analysis and/or non-trusted documentation.
|
||||||
|
* We believe there must be a union, enum, and interface (stubbed only guesses at PDB_IDs and can
|
||||||
|
* be incorrectly assigned) that are similar to the 0x1608 and 0x1609 class and struct classes,
|
||||||
|
* and yet similar to their older versions of union, enum, and interface as well.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* This class represents the VS19 <B>MsType</B> flavor of Enum type. (At this time,
|
||||||
|
* PDB_ID is guessed to be an enum similar to {@link EnumMsType}, eliminating
|
||||||
|
* the redundant count field, and adding other unknown field parsing.)
|
||||||
|
* <P>
|
||||||
|
* Note: we do not necessarily understand each of these data type classes. Refer to the
|
||||||
|
* base class for more information.
|
||||||
|
*/
|
||||||
|
public class Enum19MsType extends AbstractEnumMsType {
|
||||||
|
|
||||||
|
public static final int PDB_ID = 0x160b;
|
||||||
|
|
||||||
|
protected String mangledName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for this type.
|
||||||
|
* @param pdb {@link AbstractPdb} to which this type belongs.
|
||||||
|
* @param reader {@link PdbByteReader} from which this type is deserialized.
|
||||||
|
* @throws PdbException upon error parsing a field.
|
||||||
|
*/
|
||||||
|
public Enum19MsType(AbstractPdb pdb, PdbByteReader reader) throws PdbException {
|
||||||
|
super(pdb, reader);
|
||||||
|
property = new MsProperty(reader);
|
||||||
|
int x = reader.parseUnsignedShortVal(); //unknown
|
||||||
|
underlyingRecordNumber = RecordNumber.parse(pdb, reader, RecordCategory.TYPE, 32);
|
||||||
|
fieldDescriptorListRecordNumber = RecordNumber.parse(pdb, reader, RecordCategory.TYPE, 32);
|
||||||
|
//TODO: has more... guessing below... commented out some other conditions, but we
|
||||||
|
// might want to investigate if any data hits them.
|
||||||
|
if (reader.hasMoreNonPad()) {
|
||||||
|
name = reader.parseString(pdb, StringParseType.StringNt);
|
||||||
|
if (reader.hasMoreNonPad()) {
|
||||||
|
// Additional parsing
|
||||||
|
mangledName = reader.parseString(pdb, StringParseType.StringNt);
|
||||||
|
}
|
||||||
|
// else if (reader.hasMore()) {
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
// else {
|
||||||
|
// }
|
||||||
|
reader.skipPadding();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getPdbId() {
|
||||||
|
return PDB_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the mangled name field
|
||||||
|
* @return Mangled name.
|
||||||
|
*/
|
||||||
|
public String getMangledName() {
|
||||||
|
return mangledName;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,109 @@
|
||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.app.util.bin.format.pdb2.pdbreader.type;
|
||||||
|
|
||||||
|
import ghidra.app.util.bin.format.pdb2.pdbreader.*;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO this record type is a guess, using only data (no documentation) in its crafting.
|
||||||
|
* Thus, it can be cleaned up using trusted, msft-originated documentation if it becomes
|
||||||
|
* available and/or using more data analysis and/or non-trusted documentation.
|
||||||
|
* We believe there must be a union, enum, and interface (stubbed only guesses at PDB_IDs and can
|
||||||
|
* be incorrectly assigned) that are similar to the 0x1608 and 0x1609 class and struct classes,
|
||||||
|
* and yet similar to their older versions of union, enum, and interface as well.
|
||||||
|
* TODO: If this is a actual record type (for VS19), then we need to test it and to consider an
|
||||||
|
* abstract interface type (and also consider whether the emit should belong in the abstract
|
||||||
|
* composite type).
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* This class represents the VS19 <B>MsType</B> flavor of Interface type. (At this time,
|
||||||
|
* PDB_ID is guessed to be a class similar to {@link InterfaceMsType}, eliminating
|
||||||
|
* the redundant count field, and adding other unknown field parsing.)
|
||||||
|
* <P>
|
||||||
|
* Note that class, struct, and interface are very closed related and have many of the same
|
||||||
|
* constructs and parsing procedures. However, they are separate. If any of the internals
|
||||||
|
* of one of these is changed, it is highly suggested that the others be changed as well as
|
||||||
|
* there is not code-shared between these other than by code duplication.
|
||||||
|
* <P>
|
||||||
|
* Note: we do not necessarily understand each of these data type classes. Refer to the
|
||||||
|
* base class for more information.
|
||||||
|
*/
|
||||||
|
public class Interface19MsType extends AbstractCompositeMsType {
|
||||||
|
|
||||||
|
public static final int PDB_ID = 0x160c;
|
||||||
|
|
||||||
|
private static final String TYPE_STRING = "interface";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for this type.
|
||||||
|
* @param pdb {@link AbstractPdb} to which this type belongs.
|
||||||
|
* @param reader {@link PdbByteReader} from which this type is deserialized.
|
||||||
|
* @throws PdbException upon error parsing a field.
|
||||||
|
*/
|
||||||
|
public Interface19MsType(AbstractPdb pdb, PdbByteReader reader) throws PdbException {
|
||||||
|
super(pdb, reader);
|
||||||
|
property = new MsProperty(reader);
|
||||||
|
int x = reader.parseUnsignedShortVal(); //unknown
|
||||||
|
fieldDescriptorListRecordNumber = RecordNumber.parse(pdb, reader, RecordCategory.TYPE, 32);
|
||||||
|
derivedFromListRecordNumber = RecordNumber.parse(pdb, reader, RecordCategory.TYPE, 32);
|
||||||
|
vShapeTableRecordNumber = RecordNumber.parse(pdb, reader, RecordCategory.TYPE, 32);
|
||||||
|
//TODO: has more... guessing below... commented out some other conditions, but we
|
||||||
|
// might want to investigate if any data hits them.
|
||||||
|
Numeric numericUnknown = new Numeric(reader); //unknown. Might even be just a short.
|
||||||
|
Numeric numeric = new Numeric(reader);
|
||||||
|
if (!numeric.isIntegral()) {
|
||||||
|
throw new PdbException("Expecting integral numeric");
|
||||||
|
}
|
||||||
|
size = numeric.getIntegral();
|
||||||
|
if (reader.hasMoreNonPad()) {
|
||||||
|
name = reader.parseString(pdb, StringParseType.StringNt);
|
||||||
|
if (reader.hasMoreNonPad()) {
|
||||||
|
mangledName = reader.parseString(pdb, StringParseType.StringNt);
|
||||||
|
}
|
||||||
|
// else if (reader.hasMore()) {
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
// else {
|
||||||
|
// }
|
||||||
|
reader.skipPadding();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getPdbId() {
|
||||||
|
return PDB_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void emit(StringBuilder builder, Bind bind) {
|
||||||
|
StringBuilder myBuilder = new StringBuilder();
|
||||||
|
myBuilder.append(getTypeString());
|
||||||
|
myBuilder.append(" ");
|
||||||
|
myBuilder.append(name);
|
||||||
|
myBuilder.append("<");
|
||||||
|
myBuilder.append(property);
|
||||||
|
myBuilder.append(">");
|
||||||
|
AbstractMsType fieldType = getFieldDescriptorListType();
|
||||||
|
myBuilder.append(fieldType);
|
||||||
|
myBuilder.append(" ");
|
||||||
|
builder.insert(0, myBuilder);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getTypeString() {
|
||||||
|
return TYPE_STRING;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,82 @@
|
||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.app.util.bin.format.pdb2.pdbreader.type;
|
||||||
|
|
||||||
|
import ghidra.app.util.bin.format.pdb2.pdbreader.*;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO this record type is a guess, using only data (no documentation) in its crafting.
|
||||||
|
* Thus, it can be cleaned up using trusted, msft-originated documentation if it becomes
|
||||||
|
* available and/or using more data analysis and/or non-trusted documentation.
|
||||||
|
* /We are fairly certain that 0x1609 is some sort of struct, but it could be a typedef struct.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* This class represents the VS19 <B>MsType</B> flavor of C/C++ Struct type. (At this time,
|
||||||
|
* PDB_ID is guessed to be a structure similar to {@link StructureMsType}, eliminating
|
||||||
|
* the redundant count field, and adding other unknown field parsing.)
|
||||||
|
* <P>
|
||||||
|
* Note that class, struct, and interface are very closed related and have many of the same
|
||||||
|
* constructs and parsing procedures. However, they are separate. If any of the internals
|
||||||
|
* of one of these is changed, it is highly suggested that the others be changed as well as
|
||||||
|
* there is not code-shared between these other than by code duplication.
|
||||||
|
* <P>
|
||||||
|
* Note: we do not necessarily understand each of these data type classes. Refer to the
|
||||||
|
* base class for more information.
|
||||||
|
*/
|
||||||
|
public class Structure19MsType extends AbstractStructureMsType {
|
||||||
|
|
||||||
|
public static final int PDB_ID = 0x1609;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for this type.
|
||||||
|
* @param pdb {@link AbstractPdb} to which this type belongs.
|
||||||
|
* @param reader {@link PdbByteReader} from which this type is deserialized.
|
||||||
|
* @throws PdbException upon error parsing a field.
|
||||||
|
*/
|
||||||
|
public Structure19MsType(AbstractPdb pdb, PdbByteReader reader) throws PdbException {
|
||||||
|
super(pdb, reader);
|
||||||
|
property = new MsProperty(reader);
|
||||||
|
int x = reader.parseUnsignedShortVal(); //unknown
|
||||||
|
fieldDescriptorListRecordNumber = RecordNumber.parse(pdb, reader, RecordCategory.TYPE, 32);
|
||||||
|
derivedFromListRecordNumber = RecordNumber.parse(pdb, reader, RecordCategory.TYPE, 32);
|
||||||
|
vShapeTableRecordNumber = RecordNumber.parse(pdb, reader, RecordCategory.TYPE, 32);
|
||||||
|
//TODO: has more... guessing below... commented out some other conditions, but we
|
||||||
|
// might want to investigate if any data hits them.
|
||||||
|
Numeric numericUnknown = new Numeric(reader); //unknown. Might even be just a short.
|
||||||
|
Numeric numeric = new Numeric(reader);
|
||||||
|
if (!numeric.isIntegral()) {
|
||||||
|
throw new PdbException("Expecting integral numeric");
|
||||||
|
}
|
||||||
|
size = numeric.getIntegral();
|
||||||
|
if (reader.hasMoreNonPad()) {
|
||||||
|
name = reader.parseString(pdb, StringParseType.StringNt);
|
||||||
|
if (reader.hasMoreNonPad()) {
|
||||||
|
mangledName = reader.parseString(pdb, StringParseType.StringNt);
|
||||||
|
}
|
||||||
|
// else if (reader.hasMore()) {
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
// else {
|
||||||
|
// }
|
||||||
|
reader.skipPadding();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getPdbId() {
|
||||||
|
return PDB_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,83 @@
|
||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.app.util.bin.format.pdb2.pdbreader.type;
|
||||||
|
|
||||||
|
import ghidra.app.util.bin.format.pdb2.pdbreader.*;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO this record type is a guess, using only data (no documentation) in its crafting.
|
||||||
|
* Thus, it can be cleaned up using trusted, msft-originated documentation if it becomes
|
||||||
|
* available and/or using more data analysis and/or non-trusted documentation.
|
||||||
|
* We believe there must be a union, enum, and interface (stubbed only guesses at PDB_IDs and can
|
||||||
|
* be incorrectly assigned) that are similar to the 0x1608 and 0x1609 class and struct classes,
|
||||||
|
* and yet similar to their older versions of union, enum, and interface as well.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* This class represents the VS19 <B>MsType</B> flavor of C/C++ Union type. (At this time,
|
||||||
|
* PDB_ID is guessed to be an enum similar to {@link EnumMsType}, eliminating
|
||||||
|
* the redundant count field, and adding other unknown field parsing.)
|
||||||
|
* <P>
|
||||||
|
* Note that class, struct, and interface are very closed related and have many of the same
|
||||||
|
* constructs and parsing procedures. However, they are separate. If any of the internals
|
||||||
|
* of one of these is changed, it is highly suggested that the others be changed as well as
|
||||||
|
* there is not code-shared between these other than by code duplication.
|
||||||
|
* <P>
|
||||||
|
* Note: we do not necessarily understand each of these data type classes. Refer to the
|
||||||
|
* base class for more information.
|
||||||
|
*/
|
||||||
|
public class Union19MsType extends AbstractUnionMsType {
|
||||||
|
|
||||||
|
public static final int PDB_ID = 0x160a;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for this type.
|
||||||
|
* @param pdb {@link AbstractPdb} to which this type belongs.
|
||||||
|
* @param reader {@link PdbByteReader} from which this type is deserialized.
|
||||||
|
* @throws PdbException upon error parsing a field.
|
||||||
|
*/
|
||||||
|
public Union19MsType(AbstractPdb pdb, PdbByteReader reader) throws PdbException {
|
||||||
|
super(pdb, reader);
|
||||||
|
property = new MsProperty(reader);
|
||||||
|
int x = reader.parseUnsignedShortVal(); //unknown
|
||||||
|
fieldDescriptorListRecordNumber = RecordNumber.parse(pdb, reader, RecordCategory.TYPE, 32);
|
||||||
|
// no derivedFromListRecordNumber or vShapeTableRecordNumber
|
||||||
|
//TODO: has more... guessing below... commented out some other conditions, but we
|
||||||
|
// might want to investigate if any data hits them.
|
||||||
|
Numeric numericUnknown = new Numeric(reader); //unknown. Might even be just a short.
|
||||||
|
Numeric numeric = new Numeric(reader);
|
||||||
|
if (!numeric.isIntegral()) {
|
||||||
|
throw new PdbException("Expecting integral numeric");
|
||||||
|
}
|
||||||
|
size = numeric.getIntegral();
|
||||||
|
if (reader.hasMoreNonPad()) {
|
||||||
|
name = reader.parseString(pdb, StringParseType.StringNt);
|
||||||
|
if (reader.hasMoreNonPad()) {
|
||||||
|
mangledName = reader.parseString(pdb, StringParseType.StringNt);
|
||||||
|
}
|
||||||
|
// else if (reader.hasMore()) {
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
// else {
|
||||||
|
// }
|
||||||
|
reader.skipPadding();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getPdbId() {
|
||||||
|
return PDB_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -135,16 +135,36 @@ public class ArgumentsListTypeApplier extends MsTypeApplier {
|
||||||
|
|
||||||
DataType argDataType = argApplier.getDataType();
|
DataType argDataType = argApplier.getDataType();
|
||||||
if (argDataType == null) {
|
if (argDataType == null) {
|
||||||
String message =
|
applicator.appendLogMsg(
|
||||||
"PDB Warning: No type conversion for " + argApplier.getMsType().toString() +
|
"PDB Warning: No type conversion for " + argApplier.getMsType().toString() +
|
||||||
" for parameter " + parameterCount + " of " + functionDefinition.getName();
|
" for parameter " + parameterCount + " of " + functionDefinition.getName());
|
||||||
applicator.appendLogMsg(message);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ParameterDefinition parameterDefinition =
|
try {
|
||||||
new ParameterDefinitionImpl(null, argDataType, "");
|
ParameterDefinition parameterDefinition =
|
||||||
parameterDefinitionList.add(parameterDefinition);
|
new ParameterDefinitionImpl(null, argDataType, "");
|
||||||
parameterCount++;
|
parameterDefinitionList.add(parameterDefinition);
|
||||||
|
parameterCount++;
|
||||||
|
}
|
||||||
|
catch (IllegalArgumentException e) {
|
||||||
|
try {
|
||||||
|
DataType substitute =
|
||||||
|
Undefined.getUndefinedDataType(argDataType.getLength());
|
||||||
|
ParameterDefinition parameterDefinition =
|
||||||
|
new ParameterDefinitionImpl(null, substitute, "");
|
||||||
|
parameterDefinitionList.add(parameterDefinition);
|
||||||
|
parameterCount++;
|
||||||
|
applicator.appendLogMsg("PDB Warning: Could not apply type " + argDataType +
|
||||||
|
" for parameter " + parameterCount + " of " +
|
||||||
|
functionDefinition.getName() + ". Using undefined type instead.");
|
||||||
|
}
|
||||||
|
catch (IllegalArgumentException e1) {
|
||||||
|
applicator.appendLogMsg("PDB Warning: Could not apply type " + argDataType +
|
||||||
|
" for parameter " + parameterCount + " of " +
|
||||||
|
functionDefinition.getName() + ". Undefined failed: " + e1);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
functionDefinition.setArguments(parameterDefinitionList.toArray(
|
functionDefinition.setArguments(parameterDefinitionList.toArray(
|
||||||
|
|
|
@ -309,7 +309,8 @@ public class FunctionSymbolApplier extends MsSymbolApplier {
|
||||||
new ApplyFunctionSignatureCmd(address, def, SourceType.IMPORTED);
|
new ApplyFunctionSignatureCmd(address, def, SourceType.IMPORTED);
|
||||||
if (!sigCmd.applyTo(applicator.getProgram(), monitor)) {
|
if (!sigCmd.applyTo(applicator.getProgram(), monitor)) {
|
||||||
applicator.appendLogMsg(
|
applicator.appendLogMsg(
|
||||||
"failed to apply signature to function at address " + address.toString());
|
"PDB Warning: Failed to apply signature to function at address " + address +
|
||||||
|
" due to " + sigCmd.getStatusMsg() + "; dataType: " + def.getName());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -552,8 +552,7 @@ public class PdbApplicator {
|
||||||
int num = pdb.getDebugInfo().getNumModules();
|
int num = pdb.getDebugInfo().getNumModules();
|
||||||
for (int index = 1; index <= num; index++) {
|
for (int index = 1; index <= num; index++) {
|
||||||
monitor.checkCanceled();
|
monitor.checkCanceled();
|
||||||
String moduleName =
|
String moduleName = pdb.getDebugInfo().getModuleInformation(index).getModuleName();
|
||||||
pdb.getDebugInfo().getModuleInformation(index).getModuleName();
|
|
||||||
categoryNames.add(moduleName);
|
categoryNames.add(moduleName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1266,7 +1265,9 @@ public class PdbApplicator {
|
||||||
NamespaceUtils.getNonFunctionNamespace(program, path.getParent());
|
NamespaceUtils.getNonFunctionNamespace(program, path.getParent());
|
||||||
if (parentNamespace == null) {
|
if (parentNamespace == null) {
|
||||||
String type = isClass ? "class" : "namespace";
|
String type = isClass ? "class" : "namespace";
|
||||||
log.appendMsg("Error: failed to define " + type + ": " + path);
|
log.appendMsg(
|
||||||
|
"PDB Warning: Because parent namespace does not exist, failed to define " +
|
||||||
|
type + ": " + path);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
defineNamespace(parentNamespace, path.getName(), isClass);
|
defineNamespace(parentNamespace, path.getName(), isClass);
|
||||||
|
@ -1294,8 +1295,9 @@ public class PdbApplicator {
|
||||||
else if (namespace.getSymbol().getSymbolType() == SymbolType.NAMESPACE) {
|
else if (namespace.getSymbol().getSymbolType() == SymbolType.NAMESPACE) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
log.appendMsg("Unable to create class namespace due to conflicting symbol: " +
|
log.appendMsg(
|
||||||
namespace.getName(true));
|
"PDB Warning: Unable to create class namespace due to conflicting symbol: " +
|
||||||
|
namespace.getName(true));
|
||||||
}
|
}
|
||||||
else if (isClass) {
|
else if (isClass) {
|
||||||
symbolTable.createClass(parentNamespace, name, SourceType.IMPORTED);
|
symbolTable.createClass(parentNamespace, name, SourceType.IMPORTED);
|
||||||
|
@ -1305,8 +1307,9 @@ public class PdbApplicator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (InvalidInputException | DuplicateNameException e) {
|
catch (InvalidInputException | DuplicateNameException e) {
|
||||||
log.appendMsg("Unable to create class namespace: " + parentNamespace.getName(true) +
|
log.appendMsg(
|
||||||
Namespace.DELIMITER + name + " due to exception: " + e.toString());
|
"PDB Warning: Unable to create class namespace due to exception: " + e.toString() +
|
||||||
|
"; Namespace: " + parentNamespace.getName(true) + Namespace.DELIMITER + name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1407,7 +1410,7 @@ public class PdbApplicator {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
catch (InvalidInputException e) {
|
catch (InvalidInputException e) {
|
||||||
log.appendMsg("Unable to create symbol: " + e.getMessage());
|
log.appendMsg("PDB Warning: Unable to create symbol: " + e.getMessage());
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1532,7 +1535,8 @@ public class PdbApplicator {
|
||||||
namespace, name, SourceType.IMPORTED);
|
namespace, name, SourceType.IMPORTED);
|
||||||
}
|
}
|
||||||
catch (InvalidInputException e) {
|
catch (InvalidInputException e) {
|
||||||
appendLogMsg("Unable to create symbol " + symbolPathString + " at " + address);
|
log.appendMsg("PDB Warning: Unable to create symbol at " + address +
|
||||||
|
" due to exception: " + e.toString() + "; symbolPathName: " + symbolPathString);
|
||||||
}
|
}
|
||||||
return symbol;
|
return symbol;
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,11 +93,13 @@ public class PointerTypeApplier extends MsTypeApplier {
|
||||||
if (underlyingType == null) {
|
if (underlyingType == null) {
|
||||||
// TODO: we have seen underlyingTypeApplier is for NoTypeApplier for VtShapeMsType
|
// TODO: we have seen underlyingTypeApplier is for NoTypeApplier for VtShapeMsType
|
||||||
// Figure it out, and perhaps create an applier that creates a structure or something?
|
// Figure it out, and perhaps create an applier that creates a structure or something?
|
||||||
return new VoidDataType(applicator.getDataTypeManager());
|
underlyingType = applicator.getPdbPrimitiveTypeApplicator().getVoidType();
|
||||||
// throw new PdbException("Underlying type missing for pointer.");
|
applicator.appendLogMsg(
|
||||||
|
"PDB Warning: No type conversion for " + underlyingApplier.getMsType().toString() +
|
||||||
|
" as underlying type for pointer. Using void.");
|
||||||
}
|
}
|
||||||
|
|
||||||
int size = getSizeInt();
|
int size = type.getSize().intValueExact();
|
||||||
if (size == applicator.getDataOrganization().getPointerSize()) {
|
if (size == applicator.getDataOrganization().getPointerSize()) {
|
||||||
size = -1; // Use default
|
size = -1; // Use default
|
||||||
}
|
}
|
||||||
|
|
|
@ -494,6 +494,29 @@ public class TypeApplierFactory {
|
||||||
case UserDefinedTypeModuleSourceAndLineMsType.PDB_ID:
|
case UserDefinedTypeModuleSourceAndLineMsType.PDB_ID:
|
||||||
applier = new UdtSourceLineTypeApplier(applicator, type);
|
applier = new UdtSourceLineTypeApplier(applicator, type);
|
||||||
break;
|
break;
|
||||||
|
case Class19MsType.PDB_ID:
|
||||||
|
applier = new CompositeTypeApplier(applicator, (Class19MsType) type);
|
||||||
|
break;
|
||||||
|
case Structure19MsType.PDB_ID:
|
||||||
|
applier = new CompositeTypeApplier(applicator, (Structure19MsType) type);
|
||||||
|
break;
|
||||||
|
// TODO: the following three types are only hypothetical and might be in the wrong
|
||||||
|
// order with the wrong PDB_IDs and the wrong internal elements and parsing.
|
||||||
|
// These are here as partial implementations until they are seen and can be
|
||||||
|
// cleaned up and put into service.
|
||||||
|
// case Union19MsType.PDB_ID:
|
||||||
|
// applier = new CompositeTypeApplier(applicator, (Union19MsType) type);
|
||||||
|
// break;
|
||||||
|
// case Enum19MsType.PDB_ID:
|
||||||
|
// applier = new EnumTypeApplier(applicator, (Enum19MsType) type);
|
||||||
|
// break;
|
||||||
|
// case Interface19MsType.PDB_ID:
|
||||||
|
// // TODO InterfaceTypeApplier does not exist, and the two types we would
|
||||||
|
// // want to send it would need to either be abstracted to one abstract type
|
||||||
|
// // or a generic AbstractMsType would have to be sent and then verified
|
||||||
|
// // internal to the applier.
|
||||||
|
// applier = new InterfaceTypeApplier(applicator, (Interface19MsType) type);
|
||||||
|
// break;
|
||||||
|
|
||||||
// If all of the above are enabled, this should never happen (unless we missed
|
// If all of the above are enabled, this should never happen (unless we missed
|
||||||
// something or MSFT has added new in a version we do not handle.
|
// something or MSFT has added new in a version we do not handle.
|
||||||
|
|
|
@ -401,6 +401,29 @@ public class TypesTest extends AbstractGenericTest {
|
||||||
assertEquals("class ClassName<2,packed ctor>DummyMsType", result);
|
assertEquals("class ClassName<2,packed ctor>DummyMsType", result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO: Might need adjusting fields of record are understood.
|
||||||
|
@Test
|
||||||
|
public void testClass19MsType() throws Exception {
|
||||||
|
PdbByteWriter writer = new PdbByteWriter();
|
||||||
|
writer.putUnsignedShort(Class19MsType.PDB_ID);
|
||||||
|
byte[] propertyBuffer = createMsPropertyBuffer();
|
||||||
|
writer.putBytes(propertyBuffer);
|
||||||
|
writer.putUnsignedShort(0); // unknown field
|
||||||
|
writer.putUnsignedInt(4096); // Type index of field descriptor list.
|
||||||
|
writer.putUnsignedInt(4096); // If not zero, is type index of derived-from list
|
||||||
|
writer.putUnsignedInt(vtShapeMsType1); // Type index of the VtShapeMsType (vshape table).
|
||||||
|
writer.putNumeric(new BigInteger("0", 16), 0x8002); // unk field. Not sure if Numeric
|
||||||
|
writer.putNumeric(new BigInteger("10", 16), 0x8002); // size of class.
|
||||||
|
writer.putNullTerminatedString("ClassName");
|
||||||
|
writer.putNullTerminatedString("OtherName");
|
||||||
|
writer.putAlign(2);
|
||||||
|
PdbByteReader reader = new PdbByteReader(writer.get());
|
||||||
|
AbstractMsType type = typeParser.parse(reader);
|
||||||
|
assertEquals(type instanceof Class19MsType, true);
|
||||||
|
String result = type.toString().trim();
|
||||||
|
assertEquals("class ClassName<packed ctor>DummyMsType", result);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testStructure16MsType() throws Exception {
|
public void testStructure16MsType() throws Exception {
|
||||||
PdbByteWriter writer = new PdbByteWriter();
|
PdbByteWriter writer = new PdbByteWriter();
|
||||||
|
@ -463,6 +486,29 @@ public class TypesTest extends AbstractGenericTest {
|
||||||
assertEquals("struct StructureName<2,packed ctor>DummyMsType", result);
|
assertEquals("struct StructureName<2,packed ctor>DummyMsType", result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO: Might need adjusting fields of record are understood.
|
||||||
|
@Test
|
||||||
|
public void testStructure19MsType() throws Exception {
|
||||||
|
PdbByteWriter writer = new PdbByteWriter();
|
||||||
|
writer.putUnsignedShort(Structure19MsType.PDB_ID);
|
||||||
|
byte[] propertyBuffer = createMsPropertyBuffer();
|
||||||
|
writer.putBytes(propertyBuffer);
|
||||||
|
writer.putUnsignedShort(0); // unknown field
|
||||||
|
writer.putUnsignedInt(4096); // Type index of field descriptor list.
|
||||||
|
writer.putUnsignedInt(4096); // If not zero, is type index of derived-from list
|
||||||
|
writer.putUnsignedInt(vtShapeMsType1); // Type index of the VtShapeMsType (vshape table).
|
||||||
|
writer.putNumeric(new BigInteger("0", 16), 0x8002); // unk field. Not sure if Numeric
|
||||||
|
writer.putNumeric(new BigInteger("10", 16), 0x8002); // size of structure.
|
||||||
|
writer.putNullTerminatedString("StructureName");
|
||||||
|
writer.putNullTerminatedString("OtherName");
|
||||||
|
writer.putAlign(2);
|
||||||
|
PdbByteReader reader = new PdbByteReader(writer.get());
|
||||||
|
AbstractMsType type = typeParser.parse(reader);
|
||||||
|
assertEquals(type instanceof Structure19MsType, true);
|
||||||
|
String result = type.toString().trim();
|
||||||
|
assertEquals("struct StructureName<packed ctor>DummyMsType", result);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testInterfaceMsType() throws Exception {
|
public void testInterfaceMsType() throws Exception {
|
||||||
PdbByteWriter writer = new PdbByteWriter();
|
PdbByteWriter writer = new PdbByteWriter();
|
||||||
|
@ -484,15 +530,38 @@ public class TypesTest extends AbstractGenericTest {
|
||||||
assertEquals("interface InterfaceName<2,packed ctor>DummyMsType", result);
|
assertEquals("interface InterfaceName<2,packed ctor>DummyMsType", result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO: Hypothetical type... will need adjusting as record type is adjusted.
|
||||||
|
// @Test
|
||||||
|
// public void testInterface19MsType() throws Exception {
|
||||||
|
// PdbByteWriter writer = new PdbByteWriter();
|
||||||
|
// writer.putUnsignedShort(Interface19MsType.PDB_ID);
|
||||||
|
// byte[] propertyBuffer = createMsPropertyBuffer();
|
||||||
|
// writer.putBytes(propertyBuffer);
|
||||||
|
// writer.putUnsignedShort(0); // unknown field
|
||||||
|
// writer.putUnsignedInt(4096); // Type index of field descriptor list.
|
||||||
|
// writer.putUnsignedInt(4096); // If not zero, is type index of derived-from list
|
||||||
|
// writer.putUnsignedInt(vtShapeMsType1); // Type index of the VtShapeMsType (vshape table).
|
||||||
|
// writer.putNumeric(new BigInteger("0", 16), 0x8002); // unk field. Not sure if Numeric
|
||||||
|
// writer.putNumeric(new BigInteger("10", 16), 0x8002); // size of interface.
|
||||||
|
// writer.putNullTerminatedString("InterfaceName");
|
||||||
|
// writer.putNullTerminatedString("OtherName");
|
||||||
|
// writer.putAlign(2);
|
||||||
|
// PdbByteReader reader = new PdbByteReader(writer.get());
|
||||||
|
// AbstractMsType type = typeParser.parse(reader);
|
||||||
|
// assertEquals(type instanceof Interface19MsType, true);
|
||||||
|
// String result = type.toString().trim();
|
||||||
|
// assertEquals("interface InterfaceName<packed ctor>DummyMsType", result);
|
||||||
|
// }
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUnion16MsType() throws Exception {
|
public void testUnion16MsType() throws Exception {
|
||||||
PdbByteWriter writer = new PdbByteWriter();
|
PdbByteWriter writer = new PdbByteWriter();
|
||||||
writer.putUnsignedShort(Union16MsType.PDB_ID);
|
writer.putUnsignedShort(Union16MsType.PDB_ID);
|
||||||
writer.putUnsignedShort(2); // Count of number of elements in the class.
|
writer.putUnsignedShort(2); // Count of number of elements in the union.
|
||||||
writer.putUnsignedShort(4096); // Type index of field descriptor list.
|
writer.putUnsignedShort(4096); // Type index of field descriptor list.
|
||||||
byte[] propertyBuffer = createMsPropertyBuffer();
|
byte[] propertyBuffer = createMsPropertyBuffer();
|
||||||
writer.putBytes(propertyBuffer);
|
writer.putBytes(propertyBuffer);
|
||||||
writer.putNumeric(new BigInteger("10", 16), 0x8002); // size of class.
|
writer.putNumeric(new BigInteger("10", 16), 0x8002); // size of union.
|
||||||
writer.putByteLengthPrefixedString("UnionName16");
|
writer.putByteLengthPrefixedString("UnionName16");
|
||||||
writer.putPadding(2);
|
writer.putPadding(2);
|
||||||
PdbByteReader reader = new PdbByteReader(writer.get());
|
PdbByteReader reader = new PdbByteReader(writer.get());
|
||||||
|
@ -506,11 +575,11 @@ public class TypesTest extends AbstractGenericTest {
|
||||||
public void testUnionStMsType() throws Exception {
|
public void testUnionStMsType() throws Exception {
|
||||||
PdbByteWriter writer = new PdbByteWriter();
|
PdbByteWriter writer = new PdbByteWriter();
|
||||||
writer.putUnsignedShort(UnionStMsType.PDB_ID);
|
writer.putUnsignedShort(UnionStMsType.PDB_ID);
|
||||||
writer.putUnsignedShort(2); // Count of number of elements in the class.
|
writer.putUnsignedShort(2); // Count of number of elements in the union.
|
||||||
byte[] propertyBuffer = createMsPropertyBuffer();
|
byte[] propertyBuffer = createMsPropertyBuffer();
|
||||||
writer.putBytes(propertyBuffer);
|
writer.putBytes(propertyBuffer);
|
||||||
writer.putUnsignedInt(4096); // Type index of field descriptor list.
|
writer.putUnsignedInt(4096); // Type index of field descriptor list.
|
||||||
writer.putNumeric(new BigInteger("10", 16), 0x8002); // size of class.
|
writer.putNumeric(new BigInteger("10", 16), 0x8002); // size of union.
|
||||||
writer.putByteLengthPrefixedString("UnionNameSt");
|
writer.putByteLengthPrefixedString("UnionNameSt");
|
||||||
writer.putByteLengthPrefixedString("OtherNameSt");
|
writer.putByteLengthPrefixedString("OtherNameSt");
|
||||||
writer.putAlign(2);
|
writer.putAlign(2);
|
||||||
|
@ -525,11 +594,11 @@ public class TypesTest extends AbstractGenericTest {
|
||||||
public void testUnionMsType() throws Exception {
|
public void testUnionMsType() throws Exception {
|
||||||
PdbByteWriter writer = new PdbByteWriter();
|
PdbByteWriter writer = new PdbByteWriter();
|
||||||
writer.putUnsignedShort(UnionMsType.PDB_ID);
|
writer.putUnsignedShort(UnionMsType.PDB_ID);
|
||||||
writer.putUnsignedShort(2); // Count of number of elements in the class.
|
writer.putUnsignedShort(2); // Count of number of elements in the union.
|
||||||
byte[] propertyBuffer = createMsPropertyBuffer();
|
byte[] propertyBuffer = createMsPropertyBuffer();
|
||||||
writer.putBytes(propertyBuffer);
|
writer.putBytes(propertyBuffer);
|
||||||
writer.putUnsignedInt(4096); // Type index of field descriptor list.
|
writer.putUnsignedInt(4096); // Type index of field descriptor list.
|
||||||
writer.putNumeric(new BigInteger("10", 16), 0x8002); // size of class.
|
writer.putNumeric(new BigInteger("10", 16), 0x8002); // size of union.
|
||||||
writer.putNullTerminatedString("UnionName");
|
writer.putNullTerminatedString("UnionName");
|
||||||
writer.putNullTerminatedString("OtherName");
|
writer.putNullTerminatedString("OtherName");
|
||||||
writer.putAlign(2);
|
writer.putAlign(2);
|
||||||
|
@ -540,6 +609,27 @@ public class TypesTest extends AbstractGenericTest {
|
||||||
assertEquals("union UnionName<2,packed ctor>DummyMsType", result);
|
assertEquals("union UnionName<2,packed ctor>DummyMsType", result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO: Hypothetical type... will need adjusting as record type is adjusted.
|
||||||
|
// @Test
|
||||||
|
// public void testUnion19MsType() throws Exception {
|
||||||
|
// PdbByteWriter writer = new PdbByteWriter();
|
||||||
|
// writer.putUnsignedShort(Union19MsType.PDB_ID);
|
||||||
|
// byte[] propertyBuffer = createMsPropertyBuffer();
|
||||||
|
// writer.putBytes(propertyBuffer);
|
||||||
|
// writer.putUnsignedShort(0); // unknown field
|
||||||
|
// writer.putUnsignedInt(4096); // Type index of field descriptor list.
|
||||||
|
// writer.putNumeric(new BigInteger("0", 16), 0x8002); // unk field. Not sure if Numeric
|
||||||
|
// writer.putNumeric(new BigInteger("10", 16), 0x8002); // size of union.
|
||||||
|
// writer.putNullTerminatedString("UnionName");
|
||||||
|
// writer.putNullTerminatedString("OtherName");
|
||||||
|
// writer.putAlign(2);
|
||||||
|
// PdbByteReader reader = new PdbByteReader(writer.get());
|
||||||
|
// AbstractMsType type = typeParser.parse(reader);
|
||||||
|
// assertEquals(type instanceof Union19MsType, true);
|
||||||
|
// String result = type.toString().trim();
|
||||||
|
// assertEquals("union UnionName<packed ctor>DummyMsType", result);
|
||||||
|
// }
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testEnum16MsType() throws Exception {
|
public void testEnum16MsType() throws Exception {
|
||||||
PdbByteWriter writer = new PdbByteWriter();
|
PdbByteWriter writer = new PdbByteWriter();
|
||||||
|
@ -596,6 +686,26 @@ public class TypesTest extends AbstractGenericTest {
|
||||||
assertEquals("enum EnumName<2,DummyMsType,packed ctor>DummyMsType", result);
|
assertEquals("enum EnumName<2,DummyMsType,packed ctor>DummyMsType", result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO: Hypothetical type... will need adjusting as record type is adjusted.
|
||||||
|
// @Test
|
||||||
|
// public void testEnum19MsType() throws Exception {
|
||||||
|
// PdbByteWriter writer = new PdbByteWriter();
|
||||||
|
// writer.putUnsignedShort(Enum19MsType.PDB_ID);
|
||||||
|
// byte[] propertyBuffer = createMsPropertyBuffer();
|
||||||
|
// writer.putBytes(propertyBuffer);
|
||||||
|
// writer.putUnsignedShort(0); // unknown field
|
||||||
|
// writer.putUnsignedInt(4096); // Underlying type index.
|
||||||
|
// writer.putUnsignedInt(4096); // Type index of field descriptor list.
|
||||||
|
// writer.putNullTerminatedString("EnumName");
|
||||||
|
// writer.putNullTerminatedString("OtherName");
|
||||||
|
// writer.putAlign(2);
|
||||||
|
// PdbByteReader reader = new PdbByteReader(writer.get());
|
||||||
|
// AbstractMsType type = typeParser.parse(reader);
|
||||||
|
// assertEquals(type instanceof Enum19MsType, true);
|
||||||
|
// String result = type.toString().trim();
|
||||||
|
// assertEquals("enum EnumName<DummyMsType,packed ctor>DummyMsType", result);
|
||||||
|
// }
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testProcedure16MsType() throws Exception {
|
public void testProcedure16MsType() throws Exception {
|
||||||
PdbByteWriter writer = new PdbByteWriter();
|
PdbByteWriter writer = new PdbByteWriter();
|
||||||
|
|
|
@ -54,6 +54,7 @@ public class DBHandle {
|
||||||
/**
|
/**
|
||||||
* Construct a temporary database handle.
|
* Construct a temporary database handle.
|
||||||
* The saveAs method must be used to save the database.
|
* The saveAs method must be used to save the database.
|
||||||
|
* @throws IOException if a IO error occurs
|
||||||
*/
|
*/
|
||||||
public DBHandle() throws IOException {
|
public DBHandle() throws IOException {
|
||||||
this(BufferMgr.DEFAULT_BUFFER_SIZE, BufferMgr.DEFAULT_CACHE_SIZE);
|
this(BufferMgr.DEFAULT_BUFFER_SIZE, BufferMgr.DEFAULT_CACHE_SIZE);
|
||||||
|
@ -62,18 +63,23 @@ public class DBHandle {
|
||||||
/**
|
/**
|
||||||
* Construct a temporary database handle.
|
* Construct a temporary database handle.
|
||||||
* The saveAs method must be used to save the database.
|
* The saveAs method must be used to save the database.
|
||||||
|
* @param requestedBufferSize requested buffer size. Actual buffer size may vary.
|
||||||
|
* @throws IOException if a IO error occurs
|
||||||
*/
|
*/
|
||||||
public DBHandle(int requestBufferSize) throws IOException {
|
public DBHandle(int requestedBufferSize) throws IOException {
|
||||||
this(requestBufferSize, BufferMgr.DEFAULT_CACHE_SIZE);
|
this(requestedBufferSize, BufferMgr.DEFAULT_CACHE_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a temporary database handle.
|
* Construct a temporary database handle.
|
||||||
* The saveAs method must be used to save the database.
|
* The saveAs method must be used to save the database.
|
||||||
|
* @param requestedBufferSize requested buffer size. Actual buffer size may vary.
|
||||||
|
* @param approxCacheSize approximate size of cache in Bytes.
|
||||||
|
* @throws IOException if a IO error occurs
|
||||||
*/
|
*/
|
||||||
public DBHandle(int requestBufferSize, long approxCacheSize) throws IOException {
|
public DBHandle(int requestedBufferSize, long approxCacheSize) throws IOException {
|
||||||
bufferMgr =
|
bufferMgr =
|
||||||
new BufferMgr(requestBufferSize, approxCacheSize, BufferMgr.DEFAULT_CHECKPOINT_COUNT);
|
new BufferMgr(requestedBufferSize, approxCacheSize, BufferMgr.DEFAULT_CHECKPOINT_COUNT);
|
||||||
dbParms = new DBParms(bufferMgr, true);
|
dbParms = new DBParms(bufferMgr, true);
|
||||||
dbParms.set(DBParms.MASTER_TABLE_ROOT_BUFFER_ID_PARM, -1);
|
dbParms.set(DBParms.MASTER_TABLE_ROOT_BUFFER_ID_PARM, -1);
|
||||||
masterTable = new MasterTable(this);
|
masterTable = new MasterTable(this);
|
||||||
|
@ -108,7 +114,7 @@ public class DBHandle {
|
||||||
* @param recover if true an attempt will be made to recover unsaved data if the file is open for update
|
* @param recover if true an attempt will be made to recover unsaved data if the file is open for update
|
||||||
* @param monitor recovery monitor
|
* @param monitor recovery monitor
|
||||||
* @throws IOException if IO error occurs
|
* @throws IOException if IO error occurs
|
||||||
* @throws CancelledException
|
* @throws CancelledException if buffer file recovery is cancelled
|
||||||
*/
|
*/
|
||||||
public DBHandle(BufferFile bufferFile, boolean recover, TaskMonitor monitor)
|
public DBHandle(BufferFile bufferFile, boolean recover, TaskMonitor monitor)
|
||||||
throws IOException, CancelledException {
|
throws IOException, CancelledException {
|
||||||
|
@ -137,7 +143,7 @@ public class DBHandle {
|
||||||
* for non-update use. This method is provided primarily
|
* for non-update use. This method is provided primarily
|
||||||
* for testing.
|
* for testing.
|
||||||
* @param file buffer file
|
* @param file buffer file
|
||||||
* @throws IOException
|
* @throws IOException if IO error occurs
|
||||||
*/
|
*/
|
||||||
public DBHandle(File file) throws IOException {
|
public DBHandle(File file) throws IOException {
|
||||||
BufferFile bfile = new LocalBufferFile(file, true);
|
BufferFile bfile = new LocalBufferFile(file, true);
|
||||||
|
@ -159,8 +165,9 @@ public class DBHandle {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check the consistency of this database.
|
* Check the consistency of this database.
|
||||||
|
* @param monitor task monitor
|
||||||
* @return true if consistency check passed, else false
|
* @return true if consistency check passed, else false
|
||||||
* @throws CancelledException
|
* @throws CancelledException if consistency check is cancelled
|
||||||
*/
|
*/
|
||||||
public boolean isConsistent(TaskMonitor monitor) throws CancelledException {
|
public boolean isConsistent(TaskMonitor monitor) throws CancelledException {
|
||||||
int consistentCount = 0;
|
int consistentCount = 0;
|
||||||
|
@ -182,8 +189,9 @@ public class DBHandle {
|
||||||
* Rebuild database tables to resolve certain consistency problems. Use of this
|
* Rebuild database tables to resolve certain consistency problems. Use of this
|
||||||
* method does not recover lost data which may have occurred during original
|
* method does not recover lost data which may have occurred during original
|
||||||
* database corruption.
|
* database corruption.
|
||||||
|
* @param monitor task monitor
|
||||||
* @return true if rebuild succeeded, else false
|
* @return true if rebuild succeeded, else false
|
||||||
* @throws CancelledException
|
* @throws CancelledException if rebuild is cancelled
|
||||||
*/
|
*/
|
||||||
public boolean rebuild(TaskMonitor monitor) throws CancelledException {
|
public boolean rebuild(TaskMonitor monitor) throws CancelledException {
|
||||||
for (Table table : getTables()) {
|
for (Table table : getTables()) {
|
||||||
|
@ -205,8 +213,8 @@ public class DBHandle {
|
||||||
* WARNING! Use with extreme caution since this modifies
|
* WARNING! Use with extreme caution since this modifies
|
||||||
* the original file and could destroy data if used
|
* the original file and could destroy data if used
|
||||||
* improperly.
|
* improperly.
|
||||||
* @param file
|
* @param file database buffer file to be updated
|
||||||
* @throws IOException
|
* @throws IOException if IO error occurs
|
||||||
*/
|
*/
|
||||||
public static void resetDatabaseId(File file) throws IOException {
|
public static void resetDatabaseId(File file) throws IOException {
|
||||||
long databaseId = UniversalIdGenerator.nextID().getValue();
|
long databaseId = UniversalIdGenerator.nextID().getValue();
|
||||||
|
@ -226,7 +234,7 @@ public class DBHandle {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read current databaseId
|
* Read current databaseId
|
||||||
* @throws IOException
|
* @throws IOException if IO error occurs
|
||||||
*/
|
*/
|
||||||
private void readDatabaseId() throws IOException {
|
private void readDatabaseId() throws IOException {
|
||||||
try {
|
try {
|
||||||
|
@ -239,7 +247,7 @@ public class DBHandle {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns unique database ID or 0 if this is an older read-only database.
|
* @return unique database ID or 0 if this is an older read-only database.
|
||||||
*/
|
*/
|
||||||
public long getDatabaseId() {
|
public long getDatabaseId() {
|
||||||
return databaseId;
|
return databaseId;
|
||||||
|
@ -249,7 +257,8 @@ public class DBHandle {
|
||||||
* Returns the recovery changeSet data file for reading or null if one is not available.
|
* Returns the recovery changeSet data file for reading or null if one is not available.
|
||||||
* The caller must dispose of the returned file before peforming generating any new
|
* The caller must dispose of the returned file before peforming generating any new
|
||||||
* recovery snapshots.
|
* recovery snapshots.
|
||||||
* @throws IOException
|
* @return recovery changeSet data file for reading or null if one is not available.
|
||||||
|
* @throws IOException if IO error occurs
|
||||||
*/
|
*/
|
||||||
public LocalBufferFile getRecoveryChangeSetFile() throws IOException {
|
public LocalBufferFile getRecoveryChangeSetFile() throws IOException {
|
||||||
return bufferMgr.getRecoveryChangeSetFile();
|
return bufferMgr.getRecoveryChangeSetFile();
|
||||||
|
@ -262,7 +271,7 @@ public class DBHandle {
|
||||||
* @param monitor task monitor
|
* @param monitor task monitor
|
||||||
* @return true if snapshot successful or not needed, false if an active transaction prevented snapshot
|
* @return true if snapshot successful or not needed, false if an active transaction prevented snapshot
|
||||||
* @throws CancelledException if cancelled by monitor
|
* @throws CancelledException if cancelled by monitor
|
||||||
* @throws IOException
|
* @throws IOException if IO error occurs
|
||||||
*/
|
*/
|
||||||
public boolean takeRecoverySnapshot(DBChangeSet changeSet, TaskMonitor monitor)
|
public boolean takeRecoverySnapshot(DBChangeSet changeSet, TaskMonitor monitor)
|
||||||
throws CancelledException, IOException {
|
throws CancelledException, IOException {
|
||||||
|
@ -292,7 +301,8 @@ public class DBHandle {
|
||||||
* Returns a shared temporary database handle.
|
* Returns a shared temporary database handle.
|
||||||
* This temporary handle will remain open unitl either this
|
* This temporary handle will remain open unitl either this
|
||||||
* handle is closed or closeScratchPad is invoked.
|
* handle is closed or closeScratchPad is invoked.
|
||||||
* @throws IOException
|
* @return shared temporary database handle.
|
||||||
|
* @throws IOException if IO error occurs
|
||||||
*/
|
*/
|
||||||
public DBHandle getScratchPad() throws IOException {
|
public DBHandle getScratchPad() throws IOException {
|
||||||
if (scratchPad == null) {
|
if (scratchPad == null) {
|
||||||
|
@ -314,7 +324,7 @@ public class DBHandle {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add Database listener
|
* Add Database listener
|
||||||
* @param listener
|
* @param listener database listener
|
||||||
*/
|
*/
|
||||||
public void addListener(DBListener listener) {
|
public void addListener(DBListener listener) {
|
||||||
listenerList.add(listener);
|
listenerList.add(listener);
|
||||||
|
@ -388,7 +398,7 @@ public class DBHandle {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if transaction is currently active
|
* @return true if transaction is currently active
|
||||||
*/
|
*/
|
||||||
public boolean isTransactionActive() {
|
public boolean isTransactionActive() {
|
||||||
return txStarted;
|
return txStarted;
|
||||||
|
@ -414,7 +424,7 @@ public class DBHandle {
|
||||||
* @param commit if true a new checkpoint will be established, if
|
* @param commit if true a new checkpoint will be established, if
|
||||||
* false all changes since the previous checkpoint will be discarded.
|
* false all changes since the previous checkpoint will be discarded.
|
||||||
* @return true if new checkpoint established.
|
* @return true if new checkpoint established.
|
||||||
* @throws IOException
|
* @throws IOException if IO error occurs
|
||||||
*/
|
*/
|
||||||
public synchronized boolean endTransaction(long id, boolean commit) throws IOException {
|
public synchronized boolean endTransaction(long id, boolean commit) throws IOException {
|
||||||
if (id != lastTransactionID) {
|
if (id != lastTransactionID) {
|
||||||
|
@ -467,7 +477,7 @@ public class DBHandle {
|
||||||
* All upper-levels must clear table-based cached data prior to
|
* All upper-levels must clear table-based cached data prior to
|
||||||
* invoking this method.
|
* invoking this method.
|
||||||
* @return true if an undo was successful
|
* @return true if an undo was successful
|
||||||
* @throws IOException
|
* @throws IOException if IO error occurs
|
||||||
*/
|
*/
|
||||||
public synchronized boolean undo() throws IOException {
|
public synchronized boolean undo() throws IOException {
|
||||||
if (canUndo() && bufferMgr.undo(true)) {
|
if (canUndo() && bufferMgr.undo(true)) {
|
||||||
|
@ -479,14 +489,14 @@ public class DBHandle {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns number of undo-able transactions
|
* @return number of undo-able transactions
|
||||||
*/
|
*/
|
||||||
public int getAvailableUndoCount() {
|
public int getAvailableUndoCount() {
|
||||||
return bufferMgr != null ? bufferMgr.getAvailableUndoCount() : 0;
|
return bufferMgr != null ? bufferMgr.getAvailableUndoCount() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the number of redo-able transactions
|
* @return the number of redo-able transactions
|
||||||
*/
|
*/
|
||||||
public int getAvailableRedoCount() {
|
public int getAvailableRedoCount() {
|
||||||
return bufferMgr != null ? bufferMgr.getAvailableRedoCount() : 0;
|
return bufferMgr != null ? bufferMgr.getAvailableRedoCount() : 0;
|
||||||
|
@ -506,7 +516,7 @@ public class DBHandle {
|
||||||
* All upper-levels must clear table-based cached data prior to
|
* All upper-levels must clear table-based cached data prior to
|
||||||
* invoking this method.
|
* invoking this method.
|
||||||
* @return boolean
|
* @return boolean
|
||||||
* @throws IOException
|
* @throws IOException if IO error occurs
|
||||||
*/
|
*/
|
||||||
public synchronized boolean redo() throws IOException {
|
public synchronized boolean redo() throws IOException {
|
||||||
if (canRedo() && bufferMgr.redo()) {
|
if (canRedo() && bufferMgr.redo()) {
|
||||||
|
@ -565,7 +575,8 @@ public class DBHandle {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Close the database and dispose of the underlying buffer manager.
|
* Close the database and dispose of the underlying buffer manager.
|
||||||
* @param keepRecoveryData
|
* @param keepRecoveryData true if existing recovery data should be retained or false to remove
|
||||||
|
* any recovery data
|
||||||
*/
|
*/
|
||||||
public synchronized void close(boolean keepRecoveryData) {
|
public synchronized void close(boolean keepRecoveryData) {
|
||||||
closeScratchPad();
|
closeScratchPad();
|
||||||
|
@ -577,14 +588,14 @@ public class DBHandle {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if unsaved changes have been made.
|
* @return true if unsaved changes have been made.
|
||||||
*/
|
*/
|
||||||
public synchronized boolean isChanged() {
|
public synchronized boolean isChanged() {
|
||||||
return bufferMgr != null && bufferMgr.isChanged();
|
return bufferMgr != null && bufferMgr.isChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if this database handle has been closed.
|
* @return true if this database handle has been closed.
|
||||||
*/
|
*/
|
||||||
public boolean isClosed() {
|
public boolean isClosed() {
|
||||||
return bufferMgr == null;
|
return bufferMgr == null;
|
||||||
|
@ -628,7 +639,6 @@ public class DBHandle {
|
||||||
* will be written and set as read-only. The caller is responsbile for disposing the outFile if
|
* will be written and set as read-only. The caller is responsbile for disposing the outFile if
|
||||||
* this parameter is false.
|
* this parameter is false.
|
||||||
* @param monitor progress monitor
|
* @param monitor progress monitor
|
||||||
* @param associateWithNewFile if true this handle will be associated with the new file
|
|
||||||
* @throws IOException if IO error occurs
|
* @throws IOException if IO error occurs
|
||||||
* @throws CancelledException if monitor cancels operation
|
* @throws CancelledException if monitor cancels operation
|
||||||
*/
|
*/
|
||||||
|
@ -860,6 +870,8 @@ public class DBHandle {
|
||||||
/**
|
/**
|
||||||
* Returns the Table that was created with the given name or null if
|
* Returns the Table that was created with the given name or null if
|
||||||
* no such table exists.
|
* no such table exists.
|
||||||
|
* @param name of requested table
|
||||||
|
* @return table instance or null if not found
|
||||||
*/
|
*/
|
||||||
public Table getTable(String name) {
|
public Table getTable(String name) {
|
||||||
return tables.get(name);
|
return tables.get(name);
|
||||||
|
@ -896,7 +908,7 @@ public class DBHandle {
|
||||||
* Create secondary indexes as specified by the array of column indexes.
|
* Create secondary indexes as specified by the array of column indexes.
|
||||||
* @param name table name
|
* @param name table name
|
||||||
* @param schema table schema
|
* @param schema table schema
|
||||||
* @param indexedColumns index table columns or null
|
* @param indexedColumns array of column indices which should have an index associated with them
|
||||||
* @return new table instance
|
* @return new table instance
|
||||||
* @throws IOException if IO error occurs during table creation
|
* @throws IOException if IO error occurs during table creation
|
||||||
*/
|
*/
|
||||||
|
@ -996,6 +1008,7 @@ public class DBHandle {
|
||||||
* buffer size. This value may be used to instatiate a
|
* buffer size. This value may be used to instatiate a
|
||||||
* new BufferFile which is compatible with this database
|
* new BufferFile which is compatible with this database
|
||||||
* when using the saveAs method.
|
* when using the saveAs method.
|
||||||
|
* @return buffer size utilized by this database
|
||||||
*/
|
*/
|
||||||
public int getBufferSize() {
|
public int getBufferSize() {
|
||||||
return bufferMgr.getBufferSize();
|
return bufferMgr.getBufferSize();
|
||||||
|
|
|
@ -24,7 +24,7 @@ import java.util.List;
|
||||||
* in the current tree view (collapsed). Of course, that decision would need to be balanced
|
* in the current tree view (collapsed). Of course, that decision would need to be balanced
|
||||||
* against the extra time to reload the nodes in the event that a filter is applied. Also, if
|
* against the extra time to reload the nodes in the event that a filter is applied. Also, if
|
||||||
* some external event occurs that changes the set of children for a GTreeLazyNode, you can call
|
* some external event occurs that changes the set of children for a GTreeLazyNode, you can call
|
||||||
* {@link #reload()} to refresh the node's children.
|
* {@link #unloadChildren()} to clear any previously loaded children.
|
||||||
*/
|
*/
|
||||||
public abstract class GTreeLazyNode extends GTreeNode {
|
public abstract class GTreeLazyNode extends GTreeNode {
|
||||||
|
|
||||||
|
|
|
@ -46,7 +46,7 @@ public class RestrictedValueSortedMap<K, V> implements ValueSortedMap<K, V> {
|
||||||
/**
|
/**
|
||||||
* Construct an iterator starting at a given index of the <em>sub</em> list.
|
* Construct an iterator starting at a given index of the <em>sub</em> list.
|
||||||
*
|
*
|
||||||
* @param start
|
* @param start initial iterator position
|
||||||
*/
|
*/
|
||||||
public RestrictedEntryListIterator(int start) {
|
public RestrictedEntryListIterator(int start) {
|
||||||
this.wit = wrapped.entrySet().listIterator(getLowestIndex() + start);
|
this.wit = wrapped.entrySet().listIterator(getLowestIndex() + start);
|
||||||
|
@ -125,7 +125,7 @@ public class RestrictedValueSortedMap<K, V> implements ValueSortedMap<K, V> {
|
||||||
/**
|
/**
|
||||||
* Construct an iterator starting at a given index of the <em>sub</em> list.
|
* Construct an iterator starting at a given index of the <em>sub</em> list.
|
||||||
*
|
*
|
||||||
* @param start
|
* @param start initial iterator position
|
||||||
*/
|
*/
|
||||||
public RestrictedKeyListIterator(int start) {
|
public RestrictedKeyListIterator(int start) {
|
||||||
this.wit = new RestrictedEntryListIterator(start);
|
this.wit = new RestrictedEntryListIterator(start);
|
||||||
|
@ -186,8 +186,6 @@ public class RestrictedValueSortedMap<K, V> implements ValueSortedMap<K, V> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct an iterator
|
* Construct an iterator
|
||||||
*
|
|
||||||
* @param start
|
|
||||||
*/
|
*/
|
||||||
public RestrictedValueListIterator() {
|
public RestrictedValueListIterator() {
|
||||||
this(0);
|
this(0);
|
||||||
|
@ -196,7 +194,7 @@ public class RestrictedValueSortedMap<K, V> implements ValueSortedMap<K, V> {
|
||||||
/**
|
/**
|
||||||
* Construct an iterator starting at a given index of the <em>sub</em> list.
|
* Construct an iterator starting at a given index of the <em>sub</em> list.
|
||||||
*
|
*
|
||||||
* @param start
|
* @param start initial iterator position
|
||||||
*/
|
*/
|
||||||
public RestrictedValueListIterator(int start) {
|
public RestrictedValueListIterator(int start) {
|
||||||
this.wit = new RestrictedEntryListIterator(start);
|
this.wit = new RestrictedEntryListIterator(start);
|
||||||
|
|
|
@ -24,8 +24,8 @@ import java.util.*;
|
||||||
* This is an extension of {@link Map} where entries are sorted by value, rather than by key. Such a
|
* This is an extension of {@link Map} where entries are sorted by value, rather than by key. Such a
|
||||||
* map may be useful as a priority queue where the cost of an entry may change over time. As such,
|
* map may be useful as a priority queue where the cost of an entry may change over time. As such,
|
||||||
* the collections returned by {@link #entrySet()}, {@link #keySet()}, and {@link #values()} all
|
* the collections returned by {@link #entrySet()}, {@link #keySet()}, and {@link #values()} all
|
||||||
* extend {@link Deque}. The order of the entries will be updated on any call to {@link #put(Object,
|
* extend {@link Deque}. The order of the entries will be updated on any call to {@link Map#put(Object, Object)},
|
||||||
* Object))}, or a call to {@link Collection#add(Object)} on the entry set. Additionally, if the
|
* or a call to {@link Collection#add(Object)} on the entry set. Additionally, if the
|
||||||
* values are mutable objects, whose order may change, there is an {@link #update(Object)} method,
|
* values are mutable objects, whose order may change, there is an {@link #update(Object)} method,
|
||||||
* which notifies the map that the given key may need to be repositioned. The associated collections
|
* which notifies the map that the given key may need to be repositioned. The associated collections
|
||||||
* also extend the {@link List} interface, providing fairly efficient implementations of
|
* also extend the {@link List} interface, providing fairly efficient implementations of
|
||||||
|
|
|
@ -39,7 +39,7 @@ import sun.security.x509.*;
|
||||||
* suffice.
|
* suffice.
|
||||||
* <p>
|
* <p>
|
||||||
* <b>NOTE:</b> This class makes direct use of classes within the
|
* <b>NOTE:</b> This class makes direct use of classes within the
|
||||||
* {@link sun.security.x509} package thus breaking portability. While this is
|
* <code>sun.security.x509</code> package thus breaking portability. While this is
|
||||||
* not preferred, the ability to generate X.509 certificates and keystores
|
* not preferred, the ability to generate X.509 certificates and keystores
|
||||||
* appears to be absent from the standard java/javax packages.
|
* appears to be absent from the standard java/javax packages.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -31,7 +31,7 @@ public class LittleEndianDataConverter implements DataConverter {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Don't use this constructor to create new instances of this class. Use the static {@link #INSTANCE} instead
|
* Don't use this constructor to create new instances of this class. Use the static {@link #INSTANCE} instead
|
||||||
* or {@link DataConverter#getInstance(Endian)}
|
* or {@link DataConverter#getInstance(boolean)}
|
||||||
*/
|
*/
|
||||||
public LittleEndianDataConverter() {
|
public LittleEndianDataConverter() {
|
||||||
// empty
|
// empty
|
||||||
|
|
|
@ -71,7 +71,6 @@ public class FVSlider extends JSlider
|
||||||
* @param scrollPane
|
* @param scrollPane
|
||||||
* @param table
|
* @param table
|
||||||
* @param viewportUtility
|
* @param viewportUtility
|
||||||
* @param eventListener
|
|
||||||
* @param model
|
* @param model
|
||||||
* @param reader
|
* @param reader
|
||||||
* @param eventListener
|
* @param eventListener
|
||||||
|
|
|
@ -51,27 +51,27 @@ public interface AddressSetView extends Iterable<AddressRange> {
|
||||||
public boolean contains(AddressSetView rangeSet);
|
public boolean contains(AddressSetView rangeSet);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if this set is empty.
|
* @return true if this set is empty.
|
||||||
*/
|
*/
|
||||||
public boolean isEmpty();
|
public boolean isEmpty();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the minimum address for this set. Returns null if the set is empty.
|
* @return the minimum address for this set. Returns null if the set is empty.
|
||||||
*/
|
*/
|
||||||
public Address getMinAddress();
|
public Address getMinAddress();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the maximum address for this set. Returns null if the set is empty.
|
* @return the maximum address for this set. Returns null if the set is empty.
|
||||||
*/
|
*/
|
||||||
public Address getMaxAddress();
|
public Address getMaxAddress();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the number of address ranges in this set.
|
* @return the number of address ranges in this set.
|
||||||
*/
|
*/
|
||||||
public int getNumAddressRanges();
|
public int getNumAddressRanges();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an iterator over the address ranges in this address set.
|
* @return an iterator over the address ranges in this address set.
|
||||||
*/
|
*/
|
||||||
public AddressRangeIterator getAddressRanges();
|
public AddressRangeIterator getAddressRanges();
|
||||||
|
|
||||||
|
@ -120,7 +120,7 @@ public interface AddressSetView extends Iterable<AddressRange> {
|
||||||
public Iterator<AddressRange> iterator(Address start, boolean forward);
|
public Iterator<AddressRange> iterator(Address start, boolean forward);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the number of addresses in this set.
|
* @return the number of addresses in this set.
|
||||||
*/
|
*/
|
||||||
public long getNumAddresses();
|
public long getNumAddresses();
|
||||||
|
|
||||||
|
@ -128,6 +128,7 @@ public interface AddressSetView extends Iterable<AddressRange> {
|
||||||
* Returns an iterator over all addresses in this set.
|
* Returns an iterator over all addresses in this set.
|
||||||
* @param forward if true the address are return in increasing order, otherwise in
|
* @param forward if true the address are return in increasing order, otherwise in
|
||||||
* decreasing order.
|
* decreasing order.
|
||||||
|
* @return an iterator over all addresses in this set.
|
||||||
*/
|
*/
|
||||||
public AddressIterator getAddresses(boolean forward);
|
public AddressIterator getAddresses(boolean forward);
|
||||||
|
|
||||||
|
@ -136,6 +137,8 @@ public interface AddressSetView extends Iterable<AddressRange> {
|
||||||
* starting at the start address
|
* starting at the start address
|
||||||
* @param start address to start iterating at in the address set
|
* @param start address to start iterating at in the address set
|
||||||
* @param forward if true address are return from lowest to highest, else from highest to lowest
|
* @param forward if true address are return from lowest to highest, else from highest to lowest
|
||||||
|
* @return an iterator over the addresses in this address set
|
||||||
|
* starting at the start address
|
||||||
*/
|
*/
|
||||||
public AddressIterator getAddresses(Address start, boolean forward);
|
public AddressIterator getAddresses(Address start, boolean forward);
|
||||||
|
|
||||||
|
@ -143,6 +146,7 @@ public interface AddressSetView extends Iterable<AddressRange> {
|
||||||
* Determine if this address set intersects with the specified address set.
|
* Determine if this address set intersects with the specified address set.
|
||||||
*
|
*
|
||||||
* @param addrSet address set to check intersection with.
|
* @param addrSet address set to check intersection with.
|
||||||
|
* @return true if this set intersects the specified addrSet else false
|
||||||
*/
|
*/
|
||||||
public boolean intersects(AddressSetView addrSet);
|
public boolean intersects(AddressSetView addrSet);
|
||||||
|
|
||||||
|
@ -196,7 +200,7 @@ public interface AddressSetView extends Iterable<AddressRange> {
|
||||||
/**
|
/**
|
||||||
* Computes the exclusive-or of this address set with the given set. This
|
* Computes the exclusive-or of this address set with the given set. This
|
||||||
* method does not modify this address set.
|
* method does not modify this address set.
|
||||||
* @param addrSet
|
* @param addrSet address set to exclusive-or with.
|
||||||
* @return AddressSet a new address set containing all addresses that are in
|
* @return AddressSet a new address set containing all addresses that are in
|
||||||
* either this set or the given set, but not in both sets
|
* either this set or the given set, but not in both sets
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -30,7 +30,7 @@ import ghidra.util.GhidraDataConverter;
|
||||||
* the overhead of various error checks. This implementation will not wrap
|
* the overhead of various error checks. This implementation will not wrap
|
||||||
* if the end of the memory space is encountered.
|
* if the end of the memory space is encountered.
|
||||||
*
|
*
|
||||||
* The {@link #getByte(int), #getBytes(byte[], int)} methods can cause the bytes in the
|
* The {@link #getByte(int)}, {@link #getBytes(byte[], int)} methods can cause the bytes in the
|
||||||
* buffer cache if the request is outside of the current cached bytes.
|
* buffer cache if the request is outside of the current cached bytes.
|
||||||
*
|
*
|
||||||
* WARNING: The underlying MemBuffer should not change its base address. Using a
|
* WARNING: The underlying MemBuffer should not change its base address. Using a
|
||||||
|
@ -67,7 +67,7 @@ public class WrappedMemBuffer implements MemBuffer {
|
||||||
/**
|
/**
|
||||||
* Construct a wrapped MemBuffer with an adjustable base offset
|
* Construct a wrapped MemBuffer with an adjustable base offset
|
||||||
* @param buf memory buffer
|
* @param buf memory buffer
|
||||||
* @buffersize size of cache buffer - specify 0 for no buffering
|
* @param bufferSize size of cache buffer - specify 0 for no buffering
|
||||||
* @param baseOffset offset relative to the underlying buffer's start address
|
* @param baseOffset offset relative to the underlying buffer's start address
|
||||||
* (addr + baseOffset) will be the 0 index into this buffer
|
* (addr + baseOffset) will be the 0 index into this buffer
|
||||||
* @throws AddressOutOfBoundsException
|
* @throws AddressOutOfBoundsException
|
||||||
|
@ -113,10 +113,12 @@ public class WrappedMemBuffer implements MemBuffer {
|
||||||
private int computeOffset(int offset) throws MemoryAccessException {
|
private int computeOffset(int offset) throws MemoryAccessException {
|
||||||
int bufOffset = baseOffset + offset;
|
int bufOffset = baseOffset + offset;
|
||||||
if (offset > 0 && bufOffset < baseOffset) {
|
if (offset > 0 && bufOffset < baseOffset) {
|
||||||
throw new MemoryAccessException("Invalid WrappedMemBuffer, offset would wrap underlying memory buffer");
|
throw new MemoryAccessException(
|
||||||
|
"Invalid WrappedMemBuffer, offset would wrap underlying memory buffer");
|
||||||
}
|
}
|
||||||
if (offset < 0 && bufOffset > baseOffset) {
|
if (offset < 0 && bufOffset > baseOffset) {
|
||||||
throw new MemoryAccessException("Invalid WrappedMemBuffer offset, offset would wrap underlying memory buffer");
|
throw new MemoryAccessException(
|
||||||
|
"Invalid WrappedMemBuffer offset, offset would wrap underlying memory buffer");
|
||||||
}
|
}
|
||||||
return bufOffset;
|
return bufOffset;
|
||||||
}
|
}
|
||||||
|
@ -157,7 +159,8 @@ public class WrappedMemBuffer implements MemBuffer {
|
||||||
// grab from wrapped buffer, too many bytes, or no buffer
|
// grab from wrapped buffer, too many bytes, or no buffer
|
||||||
return memBuffer.getBytes(b, computeOffset(offset));
|
return memBuffer.getBytes(b, computeOffset(offset));
|
||||||
|
|
||||||
} catch (MemoryAccessException e) {
|
}
|
||||||
|
catch (MemoryAccessException e) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -186,22 +189,22 @@ public class WrappedMemBuffer implements MemBuffer {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public short getShort(int offset) throws MemoryAccessException {
|
public short getShort(int offset) throws MemoryAccessException {
|
||||||
return converter.getShort(this, computeOffset(offset));
|
return converter.getShort(this, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getInt(int offset) throws MemoryAccessException {
|
public int getInt(int offset) throws MemoryAccessException {
|
||||||
return converter.getInt(this, computeOffset(offset));
|
return converter.getInt(this, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getLong(int offset) throws MemoryAccessException {
|
public long getLong(int offset) throws MemoryAccessException {
|
||||||
return converter.getLong(this, computeOffset(offset));
|
return converter.getLong(this, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BigInteger getBigInteger(int offset, int size, boolean signed)
|
public BigInteger getBigInteger(int offset, int size, boolean signed)
|
||||||
throws MemoryAccessException {
|
throws MemoryAccessException {
|
||||||
return converter.getBigInteger(this, computeOffset(offset), size, signed);
|
return converter.getBigInteger(this, offset, size, signed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -718,7 +718,7 @@ define pcodeop coproc_moveto_Security_world_control;
|
||||||
define pcodeop coproc_moveto_Translation_table;
|
define pcodeop coproc_moveto_Translation_table;
|
||||||
define pcodeop coproc_moveto_Instruction_cache;
|
define pcodeop coproc_moveto_Instruction_cache;
|
||||||
define pcodeop coproc_moveto_Data_cache_operations;
|
define pcodeop coproc_moveto_Data_cache_operations;
|
||||||
define pcodeop coproc_moveto_Idetification_registers;
|
define pcodeop coproc_moveto_Identification_registers;
|
||||||
define pcodeop coproc_moveto_Peripheral_System;
|
define pcodeop coproc_moveto_Peripheral_System;
|
||||||
|
|
||||||
define pcodeop coproc_movefrom_Main_ID;
|
define pcodeop coproc_movefrom_Main_ID;
|
||||||
|
@ -768,7 +768,7 @@ define pcodeop coproc_movefrom_Security_world_control;
|
||||||
define pcodeop coproc_movefrom_Translation_table;
|
define pcodeop coproc_movefrom_Translation_table;
|
||||||
define pcodeop coproc_movefrom_Instruction_cache;
|
define pcodeop coproc_movefrom_Instruction_cache;
|
||||||
define pcodeop coproc_movefrom_Data_cache_operations;
|
define pcodeop coproc_movefrom_Data_cache_operations;
|
||||||
define pcodeop coproc_movefrom_Idetification_registers;
|
define pcodeop coproc_movefrom_Identification_registers;
|
||||||
define pcodeop coproc_movefrom_Peripheral_System;
|
define pcodeop coproc_movefrom_Peripheral_System;
|
||||||
|
|
||||||
mcrOperands: cpn,opc1,Rd,CRn,CRm,opc2 is CRm & opc2 & cpn & CRn & opc1 & Rd { }
|
mcrOperands: cpn,opc1,Rd,CRn,CRm,opc2 is CRm & opc2 & cpn & CRn & opc1 & Rd { }
|
||||||
|
@ -3323,7 +3323,7 @@ ArmPCRelImmed12: reloff is U23=0 & immed & rotate
|
||||||
{
|
{
|
||||||
build COND;
|
build COND;
|
||||||
t_opc2:4 = opc2; t_crm:4 = CRm;
|
t_opc2:4 = opc2; t_crm:4 = CRm;
|
||||||
coproc_moveto_Idetification_registers(Rd,t_opc2,t_crm);
|
coproc_moveto_Identification_registers(Rd,t_opc2,t_crm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -4013,7 +4013,7 @@ ArmPCRelImmed12: reloff is U23=0 & immed & rotate
|
||||||
{
|
{
|
||||||
build COND;
|
build COND;
|
||||||
t_opc2:4 = opc2; t_crm:4 = CRm;
|
t_opc2:4 = opc2; t_crm:4 = CRm;
|
||||||
Rd = coproc_movefrom_Idetification_registers(t_opc2,t_crm);
|
Rd = coproc_movefrom_Identification_registers(t_opc2,t_crm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue