Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions Handle/BNHighLevelILFunction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -666,6 +666,55 @@ public void SetExpressionAttributes(HighLevelILExpressionIndex expression , uint
attributes
);
}

/// <summary>
/// Attaches <paramref name="str"/> as the derived-string reference for <paramref name="expression"/>,
/// mirroring Python <c>HighLevelILFunction.set_derived_string_reference_for_expr</c>
/// (highlevelil.py:3014).
/// </summary>
/// <param name="expression">The expression to attach the derived string to.</param>
/// <param name="str">The derived string to attach. Must not be null.</param>
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);
}
}
}

/// <summary>
/// Removes any derived-string reference attached to <paramref name="expression"/>, mirroring
/// Python <c>HighLevelILFunction.remove_derived_string_reference_for_expr</c>
/// (highlevelil.py:3023).
/// </summary>
/// <param name="expression">The expression whose derived-string reference to clear.</param>
public void RemoveDerivedStringReferenceForExpr(HighLevelILExpressionIndex expression)
{
UIntPtr exprIndex = (UIntPtr)(ulong)expression;
NativeMethods.BNRemoveHighLevelILDerivedStringReferenceForExpr(
this.handle ,
exprIndex
);
}

public LinearViewObject CreateLinearView( DisassemblySettings? settings = null)
{
Expand Down
42 changes: 42 additions & 0 deletions NavigationExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,17 @@ public sealed class DerivedString

public ulong Length { get; }

/// <summary>
/// Constructs a value-only DerivedString with no location, mirroring Python
/// <c>DerivedString(value=..., location=None, custom_type=None)</c> for the common case of
/// attaching a derived string via
/// <see cref="HighLevelILFunction.SetDerivedStringReferenceForExpr"/>.
/// </summary>
public DerivedString(string value)
: this(value, false, 0, 0UL, 0UL)
{
}

private DerivedString(
string value,
bool locationValid,
Expand Down Expand Up @@ -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)
Expand Down
43 changes: 43 additions & 0 deletions Struct/BNHighLevelILInstruction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1496,6 +1496,49 @@ public RegisterValue Value
return this.MediumLevelIL.Value;
}
}

/// <summary>
/// The derived string this expression references, mirroring Python
/// <c>HighLevelILInstruction.derived_string_reference</c> (highlevelil.py:978). Returns
/// <c>null</c> when the expression carries no derived-string reference.
/// </summary>
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<BNDerivedString>(outPointer);
DerivedString result = DerivedString.FromNative(raw);

if (IntPtr.Zero != raw.value)
{
NativeMethods.BNFreeStringRef(raw.value);
}

return result;
}
}
}

public PossibleValueSet PossibleValues
{
Expand Down
Loading