Merge remote-tracking branch 'origin/GP-6006_ghidra1_added_new_source_type' into Ghidra_12.0

This commit is contained in:
ghidra1 2025-09-24 09:18:53 -04:00
commit 5df99853af
15 changed files with 321 additions and 183 deletions

View file

@ -116,8 +116,10 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM
* 13-Dec-2024 - version 29 Added source file manager.
* 3-Jun-2025 - version 30 Symbol Table schema V4 with external symbol data indexing
* 15-Sep-2025 - version 31 Code Mananger dropped Composites property map use
* 19-Sep-2025 - version 32 Expanded number of SourceType values and record storage affecting
* SymbolDB, FunctionDB and RefListFlagsV0
*/
static final int DB_VERSION = 31;
static final int DB_VERSION = 32;
/**
* UPGRADE_REQUIRED_BFORE_VERSION should be changed to DB_VERSION anytime the

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -46,10 +46,12 @@ abstract class FunctionAdapter {
static final byte FUNCTION_INLINE_FLAG = (byte) 0x2; // Bit 1 is flag for "is inline".
static final byte FUNCTION_NO_RETURN_FLAG = (byte) 0x4; // Bit 2 is flag for "has no return".
static final byte FUNCTION_CUSTOM_PARAM_STORAGE_FLAG = (byte) 0x8; // Bit 3 is flag for "has custom storage"
static final byte FUNCTION_SIGNATURE_SOURCE = (byte) 0x30; // Bits 4-5 are storage for "signature SourceType"
static final byte FUNCTION_SIGNATURE_SOURCE = (byte) 0x70; // Bits 4-6 are storage for "signature SourceType"
static final int FUNCTION_SIGNATURE_SOURCE_SHIFT = 4; // bit shift for flag storage of "signature SourceType"
private static final int MAX_SOURCE_VALUE = 7; // value limit based upon 3-bit storage capacity
final static Schema FUNCTION_SCHEMA = new Schema(CURRENT_VERSION, "ID",
new Field[] { LongField.INSTANCE, IntField.INSTANCE, IntField.INSTANCE, IntField.INSTANCE,
ByteField.INSTANCE, ByteField.INSTANCE, StringField.INSTANCE },
@ -94,8 +96,11 @@ abstract class FunctionAdapter {
}
static byte getSignatureSourceFlagBits(SourceType signatureSource) {
return (byte) (signatureSource
.ordinal() << FunctionAdapter.FUNCTION_SIGNATURE_SOURCE_SHIFT);
int sourceTypeId = signatureSource.getStorageId();
if (sourceTypeId > MAX_SOURCE_VALUE) {
throw new RuntimeException("Unsupported SourceType storage ID: " + sourceTypeId);
}
return (byte) (sourceTypeId << FunctionAdapter.FUNCTION_SIGNATURE_SOURCE_SHIFT);
}
static FunctionAdapter findReadOnlyAdapter(DBHandle handle, AddressMap map)

View file

@ -2445,9 +2445,9 @@ public class FunctionDB extends DatabaseObject implements Function {
SourceType getStoredSignatureSource() {
byte flags = rec.getByteValue(FunctionAdapter.FUNCTION_FLAGS_COL);
int typeOrdinal = (flags &
int sourceTypeId = (flags &
FunctionAdapter.FUNCTION_SIGNATURE_SOURCE) >>> FunctionAdapter.FUNCTION_SIGNATURE_SOURCE_SHIFT;
return SourceType.values()[typeOrdinal];
return SourceType.getSourceType(sourceTypeId);
}
@Override

View file

@ -1,13 +1,12 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -20,13 +19,23 @@ import ghidra.program.model.symbol.SourceType;
class RefListFlagsV0 {
private static final int SOURCE_LOBIT = 0x01;
// NOTE: Storage for SourceType has been expanded into upper zero-initialized bits
// with simple ProgramDB version change.
private static final int SOURCE_LOBIT = 0x01; // SourceType LO 1-bit
private static final int IS_PRIMARY = 0x02;
private static final int IS_OFFSET = 0x04;
private static final int HAS_SYMBOL_ID = 0x08;
private static final int IS_SHIFT = 0x10;
private static final int SOURCE_HIBITS = 0x60; // SourceType HI 2-bits
private static final int SOURCE_HIBIT = 0x20;
private static final int SOURCE_LOBIT_SHIFT = 0;
private static final int SOURCE_HIBITS_SHIFT = 5;
private static final int MAX_SOURCE_VALUE = 7; // value limit based upon 3-bit storage capacity
private int flags;
RefListFlagsV0(byte flags) {
@ -36,12 +45,23 @@ class RefListFlagsV0 {
public RefListFlagsV0(boolean isPrimary, boolean isOffsetRef, boolean hasSymbolID,
boolean isShiftRef, SourceType source) {
flags = 0;
if (source == SourceType.USER_DEFINED || source == SourceType.IMPORTED) {
flags |= SOURCE_LOBIT;
}
if (source == SourceType.ANALYSIS || source == SourceType.IMPORTED) {
flags |= SOURCE_HIBIT;
// Get the storage ID to be used to encode source type
// NOTE: RefListV0 uses a storage ID in some cases that differs from SourceType storage ID
int sourceId = switch (source) {
case DEFAULT -> 0;
case ANALYSIS -> 2;
default -> source.getStorageId();
};
// Encode SourceType value into split storage flags
if (sourceId > MAX_SOURCE_VALUE) {
throw new RuntimeException("Unsupported SourceType storage ID: " + sourceId);
}
int sourceTypeLoBit = (sourceId & 1) << SOURCE_LOBIT_SHIFT; // 1-bit
int sourceTypeHiBits = (sourceId >>> 1) << SOURCE_HIBITS_SHIFT; // remaining hi-bits
flags |= sourceTypeHiBits | sourceTypeLoBit;
if (isPrimary)
flags |= IS_PRIMARY;
if (isOffsetRef)
@ -57,12 +77,18 @@ class RefListFlagsV0 {
}
SourceType getSource() {
boolean isLoBit = (flags & SOURCE_LOBIT) != 0;
boolean isHiBit = (flags & SOURCE_HIBIT) != 0;
if (isHiBit) {
return isLoBit ? SourceType.IMPORTED : SourceType.ANALYSIS;
}
return isLoBit ? SourceType.USER_DEFINED : SourceType.DEFAULT;
// Decode storage ID from flags bits
int sourceTypeLoBit = (flags & SOURCE_LOBIT) >>> SOURCE_LOBIT_SHIFT; // 1-bit
int sourceTypeHiBits = (flags & SOURCE_HIBITS) >>> (SOURCE_HIBITS_SHIFT - 1); // remaining HI-bits
int sourceTypeId = sourceTypeHiBits | sourceTypeLoBit;
// NOTE: RefListV0 uses a storage ID in some cases that differs from SourceType storage ID
return switch (sourceTypeId) {
case 0 -> SourceType.DEFAULT;
case 2 -> SourceType.ANALYSIS;
default -> SourceType.getSourceType(sourceTypeId);
};
}
public boolean hasSymbolID() {

View file

@ -169,7 +169,7 @@ public abstract class MemorySymbol extends SymbolDB {
newNamespace.getID());
}
if (newSource != null) {
setSourceFlagBit(newSource);
setSourceFlagBits(newSource);
}
updatePinnedFlag(pinned);
updateRecord();

View file

@ -253,7 +253,7 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
throw new IllegalArgumentException(msg);
}
if (record != null) {
setSourceFlagBit(newSource);
setSourceFlagBits(newSource);
updateRecord();
symbolMgr.symbolSourceChanged(this);
}
@ -263,10 +263,10 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
}
}
protected void setSourceFlagBit(SourceType newSource) {
protected void setSourceFlagBits(SourceType newSource) {
byte flags = record.getByteValue(SymbolDatabaseAdapter.SYMBOL_FLAGS_COL);
byte clearBits = SymbolDatabaseAdapter.SYMBOL_SOURCE_BITS;
byte setBits = (byte) newSource.ordinal();
byte clearBits = SymbolDatabaseAdapter.SYMBOL_SOURCE_MASK;
byte setBits = SymbolDatabaseAdapter.getSourceTypeFlagsBits(newSource);
flags &= ~clearBits;
flags |= setBits;
record.setByteValue(SymbolDatabaseAdapter.SYMBOL_FLAGS_COL, flags);
@ -280,10 +280,8 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
if (record == null) {
return SourceType.DEFAULT;
}
byte sourceBits = SymbolDatabaseAdapter.SYMBOL_SOURCE_BITS;
byte flags = record.getByteValue(SymbolDatabaseAdapter.SYMBOL_FLAGS_COL);
byte adapterSource = (byte) (flags & sourceBits);
return SourceType.values()[adapterSource];
return SymbolDatabaseAdapter.decodeSourceTypeFromFlags(flags);
}
finally {
lock.release();
@ -448,8 +446,8 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
private void updateSymbolSource(DBRecord symbolRecord, SourceType source) {
byte flags = record.getByteValue(SymbolDatabaseAdapter.SYMBOL_FLAGS_COL);
flags &= ~SymbolDatabaseAdapter.SYMBOL_SOURCE_BITS;
flags |= (byte) source.ordinal();
flags &= ~SymbolDatabaseAdapter.SYMBOL_SOURCE_MASK; // clear source type bits
flags |= SymbolDatabaseAdapter.getSourceTypeFlagsBits(source);
symbolRecord.setByteValue(SymbolDatabaseAdapter.SYMBOL_FLAGS_COL, flags);
}

View file

@ -56,9 +56,18 @@ abstract class SymbolDatabaseAdapter {
static final Schema SYMBOL_SCHEMA = SymbolDatabaseAdapterV4.V4_SYMBOL_SCHEMA;
// Bits 0 & 1 are used for the source of the symbol.
static final byte SYMBOL_SOURCE_BITS = (byte) 0x3;
// Bits 0, 1 and 3 are used for the source of the symbol.
// NOTE: On the next V5 adapter revision the source type bits should be made contiguous
static final byte SYMBOL_SOURCE_LO_BITS = (byte) 0x3; // bits 0-1 of SourceType storage ID
static final byte SYMBOL_PINNED_FLAG = (byte) 0x4; // Bit 2 is flag for "anchored to address".
static final byte SYMBOL_SOURCE_HI_BIT = (byte) 0x8; // bit-3 of SourceType storage ID
static final byte SYMBOL_SOURCE_MASK = (byte) 0xB; // (01011) Storage mask for SourceType storage ID
static final int SYMBOL_SOURCE_LO_BITS_SHIFT = 0;
static final int SYMBOL_SOURCE_HI_BIT_SHIFT = 3;
static final int MAX_SOURCE_VALUE = 7; // value limit based upon 3-bit storage capacity
// Symbol type constants
static final int SYMBOL_TYPE_LABEL = SymbolType.LABEL.getID();
@ -219,6 +228,34 @@ abstract class SymbolDatabaseAdapter {
}
}
/**
* Transforms source type storage ID to V4 flag bits.
* @param sourceType source type
* @return storage ID flag bits
*/
static byte getSourceTypeFlagsBits(SourceType sourceType) {
// Encode SourceType value into split storage flags
int sourceTypeId = sourceType.getStorageId();
if (sourceTypeId > MAX_SOURCE_VALUE) {
throw new RuntimeException("Unsupported SourceType storage ID: " + sourceTypeId);
}
int sourceTypeLoBits = (sourceTypeId & 0x3) << SYMBOL_SOURCE_LO_BITS_SHIFT; // bits 0-1
int sourceTypeHiBit = (sourceTypeId >>> 2) << SYMBOL_SOURCE_HI_BIT_SHIFT; // remaining hi-bit
return (byte) (sourceTypeHiBit | sourceTypeLoBits);
}
/**
* Decode V4 flags source type
* @param flags symbol flags
* @return source type
*/
static SourceType decodeSourceTypeFromFlags(byte flags) {
int sourceTypeLoBits = (flags & SYMBOL_SOURCE_LO_BITS) >>> SYMBOL_SOURCE_LO_BITS_SHIFT; // bits 0-1
int sourceTypeHiBit = (flags & SYMBOL_SOURCE_HI_BIT) >>> (SYMBOL_SOURCE_HI_BIT_SHIFT - 2); // remaining HI-bit
int sourceTypeId = sourceTypeHiBit | sourceTypeLoBits;
return SourceType.getSourceType(sourceTypeId);
}
/**
* Instantiate a new basic symbol record. Caller is responsible for updating any related
* optional record fields and then adding to the table via the

View file

@ -97,7 +97,7 @@ class SymbolDatabaseAdapterV4 extends SymbolDatabaseAdapter {
// if (nextID == 0) {
// nextID++;
// }
// return createSymbol(nextID, name, address, namespaceID, symbolType, (byte) source.ordinal(),
// return createSymbol(nextID, name, address, namespaceID, symbolType, (byte) source.getStorageId(),
// isPrimary);
// }
@ -119,7 +119,7 @@ class SymbolDatabaseAdapterV4 extends SymbolDatabaseAdapter {
rec.setLongValue(SYMBOL_ADDR_COL, addressKey);
rec.setLongValue(SYMBOL_PARENT_ID_COL, namespaceID);
rec.setByteValue(SYMBOL_TYPE_COL, symbolType.getID());
rec.setByteValue(SYMBOL_FLAGS_COL, (byte) source.ordinal());
rec.setByteValue(SYMBOL_FLAGS_COL, getSourceTypeFlagsBits(source)); // assume non-pinned
// Sparse columns - these columns don't apply to all symbols.
// they default to null unless specifically set. Null values don't consume space.

View file

@ -15,28 +15,83 @@
*/
package ghidra.program.model.symbol;
public enum SourceType {
// WARNING WARNING: do not change the order of these enums as they are stored in the
// database by their ordinal.
import java.util.NoSuchElementException;
public enum SourceType {
// WARNING WARNING: the assigned storage IDs are used for persistent serialization.
// Any change or re-use must consider data upgrade concerns.
// The SourceType's defined below are ordered based upon their priority values.
// Priority values may be changed.
/** The object's source indicator for an auto analysis. */
ANALYSIS("Analysis", 2),
/** The object's source indicator for a user defined. */
USER_DEFINED("User Defined", 4),
/** The object's source indicator for a default. */
DEFAULT("Default", 1),
DEFAULT("Default", 1, 2),
/** The object's source indicator for an auto analysis. */
ANALYSIS("Analysis", 2, 0),
/** The object's source indicator for something that was produced with AI assistance. */
AI("AI", 2, 4),
/** The object's source indicator for an imported. */
IMPORTED("Imported", 3);
IMPORTED("Imported", 3, 3),
/** The object's source indicator for a user defined. */
USER_DEFINED("User Defined", 4, 1);
// SourceType values indexed by storageID (use null for undefined IDs).
private static SourceType[] SOURCE_BY_STORAGE_ID =
new SourceType[] { ANALYSIS, USER_DEFINED, DEFAULT, IMPORTED, AI };
private final String displayString;
private final int priority; // bigger numbers are higher priorty
private final int storageId;
private final int priority; // bigger numbers are higher priority
private SourceType(String displayString, int priority) {
/**
* {@link SourceType} constructor
* @param displayString enum display name
* @param priority unique priority among other defined enum values
* @param storageId non-negative storage ID for persistent serialization. Once an ID is
* assigned it may never be removed without serious consideration to DB upgrade transformation.
*/
private SourceType(String displayString, int priority, int storageId) {
this.displayString = displayString;
this.storageId = storageId;
this.priority = priority;
}
/** Returns a user-friendly string */
/**
* Get the SourceType which corresponds to the specified storage ID.
* @param storageId storage ID
* @return SourceType
* @throws NoSuchElementException if specified storage ID is not defined.
*/
public static SourceType getSourceType(int storageId) {
try {
SourceType source = SOURCE_BY_STORAGE_ID[storageId];
if (source != null) {
return source;
}
}
catch (ArrayIndexOutOfBoundsException e) {
// throw error below
}
throw new NoSuchElementException("SourceType storgae ID not defined: " + storageId);
}
/**
* {@return numeric priority relative to other SourceType. Higher numbers are higher priority.}
*/
public int getPriority() {
return priority;
}
/**
* {@return the storage ID which should be used for persistent serialization}
*/
public int getStorageId() {
return storageId;
}
/**
* {@return a user-friendly string}
*/
public String getDisplayString() {
return displayString;
}