diff --git a/Handle/BNHighLevelILFunction.cs b/Handle/BNHighLevelILFunction.cs
index 3c268b3..d66290b 100644
--- a/Handle/BNHighLevelILFunction.cs
+++ b/Handle/BNHighLevelILFunction.cs
@@ -666,6 +666,55 @@ public void SetExpressionAttributes(HighLevelILExpressionIndex expression , uint
attributes
);
}
+
+ ///
+ /// Attaches as the derived-string reference for ,
+ /// mirroring Python HighLevelILFunction.set_derived_string_reference_for_expr
+ /// (highlevelil.py:3014).
+ ///
+ /// The expression to attach the derived string to.
+ /// The derived string to attach. Must not be null.
+ public void SetDerivedStringReferenceForExpr(HighLevelILExpressionIndex expression, DerivedString str)
+ {
+ if (null == str)
+ {
+ throw new ArgumentNullException(nameof(str));
+ }
+
+ using (ScopedAllocator allocator = new ScopedAllocator())
+ {
+ // 1. Build the native struct; its value is a fresh BNStringRef* this method owns.
+ BNDerivedString native = str.ToNativeEx();
+
+ // 2. Pin the struct and hand it to the core.
+ IntPtr structPointer = allocator.AllocStruct(native);
+ UIntPtr exprIndex = (UIntPtr)(ulong)expression;
+ NativeMethods.BNSetHighLevelILDerivedStringReferenceForExpr(this.handle, exprIndex, structPointer);
+
+ // 3. Free the BNStringRef* this method created. Core copies/add-refs the string
+ // (Python passes owned=False; its StringRef outlives the call), so freeing here
+ // balances this method's own allocation and is safe.
+ if (IntPtr.Zero != native.value)
+ {
+ NativeMethods.BNFreeStringRef(native.value);
+ }
+ }
+ }
+
+ ///
+ /// Removes any derived-string reference attached to , mirroring
+ /// Python HighLevelILFunction.remove_derived_string_reference_for_expr
+ /// (highlevelil.py:3023).
+ ///
+ /// The expression whose derived-string reference to clear.
+ public void RemoveDerivedStringReferenceForExpr(HighLevelILExpressionIndex expression)
+ {
+ UIntPtr exprIndex = (UIntPtr)(ulong)expression;
+ NativeMethods.BNRemoveHighLevelILDerivedStringReferenceForExpr(
+ this.handle ,
+ exprIndex
+ );
+ }
public LinearViewObject CreateLinearView( DisassemblySettings? settings = null)
{
diff --git a/NavigationExtensions.cs b/NavigationExtensions.cs
index 4563a28..132993c 100644
--- a/NavigationExtensions.cs
+++ b/NavigationExtensions.cs
@@ -80,6 +80,17 @@ public sealed class DerivedString
public ulong Length { get; }
+ ///
+ /// Constructs a value-only DerivedString with no location, mirroring Python
+ /// DerivedString(value=..., location=None, custom_type=None) for the common case of
+ /// attaching a derived string via
+ /// .
+ ///
+ public DerivedString(string value)
+ : this(value, false, 0, 0UL, 0UL)
+ {
+ }
+
private DerivedString(
string value,
bool locationValid,
@@ -110,6 +121,37 @@ internal static DerivedString FromNative(BNDerivedString raw)
);
}
+ // Re-materializes this projection as a native BNDerivedString for the Set path
+ // (BNSetHighLevelILDerivedStringReferenceForExpr). The Value text is rebuilt as a fresh
+ // BNStringRef* because this projection reads eagerly and does not retain the original core
+ // handle. The caller owns that BNStringRef* and must free it (BNFreeStringRef) once the
+ // core has consumed the struct: core copies/add-refs the string, mirroring Python's
+ // owned=False borrow. custom_type is not surfaced by this read-only projection (Python
+ // CustomStringType handle is dropped), so it is left null.
+ internal BNDerivedString ToNativeEx()
+ {
+ ulong byteCount = (ulong)Encoding.UTF8.GetByteCount(this.Value);
+ IntPtr stringRef = NativeMethods.BNCreateStringRefOfLength(
+ this.Value,
+ (UIntPtr)byteCount
+ );
+
+ BNDerivedString native = new BNDerivedString();
+ native.value = stringRef;
+ native.locationValid = this.LocationValid;
+
+ if (this.LocationValid)
+ {
+ native.location.locationType = (int)this.LocationType;
+ native.location.addr = this.Address;
+ native.location.len = this.Length;
+ }
+
+ native.customType = IntPtr.Zero;
+
+ return native;
+ }
+
// Decodes a BNStringRef* as a UTF-8 string. The core hands back a NUL-terminated C
// string; UTF-8 decoding covers the non-ASCII case the rest of the binding targets.
private static string ReadStringRef(IntPtr reference)
diff --git a/Struct/BNHighLevelILInstruction.cs b/Struct/BNHighLevelILInstruction.cs
index 5d87ef1..dc49da3 100644
--- a/Struct/BNHighLevelILInstruction.cs
+++ b/Struct/BNHighLevelILInstruction.cs
@@ -1496,6 +1496,49 @@ public RegisterValue Value
return this.MediumLevelIL.Value;
}
}
+
+ ///
+ /// The derived string this expression references, mirroring Python
+ /// HighLevelILInstruction.derived_string_reference (highlevelil.py:978). Returns
+ /// null when the expression carries no derived-string reference.
+ ///
+ public DerivedString? DerivedStringReference
+ {
+ get
+ {
+ // 1. Allocate the out-struct the core writes into.
+ using (ScopedAllocator allocator = new ScopedAllocator())
+ {
+ IntPtr outPointer = allocator.AllocStruct(new BNDerivedString());
+
+ // 2. Ask the core for the reference; false means there is none.
+ UIntPtr exprIndex = (UIntPtr)(ulong)this.ExpressionIndex;
+ bool found = NativeMethods.BNGetHighLevelILDerivedStringReferenceForExpr(
+ this.ILFunction.DangerousGetHandle(),
+ exprIndex,
+ outPointer
+ );
+
+ if (!found)
+ {
+ return null;
+ }
+
+ // 3. Project the struct, then free the owned BNStringRef*. Python's StringRef
+ // takes ownership (owned=True) and frees the handle on GC; this binding reads the
+ // text eagerly, so it must free the handle itself to avoid a leak per call.
+ BNDerivedString raw = Marshal.PtrToStructure(outPointer);
+ DerivedString result = DerivedString.FromNative(raw);
+
+ if (IntPtr.Zero != raw.value)
+ {
+ NativeMethods.BNFreeStringRef(raw.value);
+ }
+
+ return result;
+ }
+ }
+ }
public PossibleValueSet PossibleValues
{