@@ -32,8 +32,8 @@ private readonly struct Configuration
3232 }
3333
3434 private readonly Configuration _config ;
35- private readonly Reader _reader ;
3635
36+ private readonly DataTargetDelegates _dataTargetDelegates ;
3737 private readonly Dictionary < string , int > _contracts = [ ] ;
3838 private readonly IReadOnlyDictionary < string , GlobalValue > _globals = new Dictionary < string , GlobalValue > ( ) ;
3939 private readonly Dictionary < DataType , Target . TypeInfo > _knownTypes = [ ] ;
@@ -43,6 +43,7 @@ private readonly struct Configuration
4343 public override DataCache ProcessedData { get ; }
4444
4545 public delegate int ReadFromTargetDelegate ( ulong address , Span < byte > bufferToFill ) ;
46+ public delegate int WriteToTargetDelegate ( ulong address , Span < byte > bufferToWrite ) ;
4647 public delegate int GetTargetThreadContextDelegate ( uint threadId , uint contextFlags , Span < byte > bufferToFill ) ;
4748
4849 /// <summary>
@@ -56,18 +57,19 @@ private readonly struct Configuration
5657 public static bool TryCreate (
5758 ulong contractDescriptor ,
5859 ReadFromTargetDelegate readFromTarget ,
60+ WriteToTargetDelegate writeToTarget ,
5961 GetTargetThreadContextDelegate getThreadContext ,
6062 [ NotNullWhen ( true ) ] out ContractDescriptorTarget ? target )
6163 {
62- Reader reader = new Reader ( readFromTarget , getThreadContext ) ;
64+ DataTargetDelegates dataTargetDelegates = new DataTargetDelegates ( readFromTarget , writeToTarget , getThreadContext ) ;
6365 if ( TryReadContractDescriptor (
6466 contractDescriptor ,
65- reader ,
67+ dataTargetDelegates ,
6668 out Configuration config ,
6769 out ContractDescriptorParser . ContractDescriptor ? descriptor ,
6870 out TargetPointer [ ] pointerData ) )
6971 {
70- target = new ContractDescriptorTarget ( config , descriptor ! , pointerData , reader ) ;
72+ target = new ContractDescriptorTarget ( config , descriptor ! , pointerData , dataTargetDelegates ) ;
7173 return true ;
7274 }
7375
@@ -89,6 +91,7 @@ public static ContractDescriptorTarget Create(
8991 ContractDescriptorParser . ContractDescriptor contractDescriptor ,
9092 TargetPointer [ ] globalPointerValues ,
9193 ReadFromTargetDelegate readFromTarget ,
94+ WriteToTargetDelegate writeToTarget ,
9295 GetTargetThreadContextDelegate getThreadContext ,
9396 bool isLittleEndian ,
9497 int pointerSize )
@@ -97,15 +100,15 @@ public static ContractDescriptorTarget Create(
97100 new Configuration { IsLittleEndian = isLittleEndian , PointerSize = pointerSize } ,
98101 contractDescriptor ,
99102 globalPointerValues ,
100- new Reader ( readFromTarget , getThreadContext ) ) ;
103+ new DataTargetDelegates ( readFromTarget , writeToTarget , getThreadContext ) ) ;
101104 }
102105
103- private ContractDescriptorTarget ( Configuration config , ContractDescriptorParser . ContractDescriptor descriptor , TargetPointer [ ] pointerData , Reader reader )
106+ private ContractDescriptorTarget ( Configuration config , ContractDescriptorParser . ContractDescriptor descriptor , TargetPointer [ ] pointerData , DataTargetDelegates dataTargetDelegates )
104107 {
105108 Contracts = new CachingContractRegistry ( this , this . TryGetContractVersion ) ;
106109 ProcessedData = new DataCache ( this ) ;
107110 _config = config ;
108- _reader = reader ;
111+ _dataTargetDelegates = dataTargetDelegates ;
109112
110113 _contracts = descriptor . Contracts ?? [ ] ;
111114
@@ -187,7 +190,7 @@ private struct GlobalValue
187190 // See docs/design/datacontracts/contract-descriptor.md
188191 private static bool TryReadContractDescriptor (
189192 ulong address ,
190- Reader reader ,
193+ DataTargetDelegates dataTargetDelegates ,
191194 out Configuration config ,
192195 out ContractDescriptorParser . ContractDescriptor ? descriptor ,
193196 out TargetPointer [ ] pointerData )
@@ -198,7 +201,7 @@ private static bool TryReadContractDescriptor(
198201
199202 // Magic - uint64_t
200203 Span < byte > buffer = stackalloc byte [ sizeof ( ulong ) ] ;
201- if ( reader . ReadFromTarget ( address , buffer ) < 0 )
204+ if ( dataTargetDelegates . ReadFromTarget ( address , buffer ) < 0 )
202205 return false ;
203206
204207 address += sizeof ( ulong ) ;
@@ -209,7 +212,7 @@ private static bool TryReadContractDescriptor(
209212 return false ;
210213
211214 // Flags - uint32_t
212- if ( ! TryRead ( address , isLittleEndian , reader , out uint flags ) )
215+ if ( ! TryRead ( address , isLittleEndian , dataTargetDelegates , out uint flags ) )
213216 return false ;
214217
215218 address += sizeof ( uint ) ;
@@ -220,19 +223,19 @@ private static bool TryReadContractDescriptor(
220223 config = new Configuration { IsLittleEndian = isLittleEndian , PointerSize = pointerSize } ;
221224
222225 // Descriptor size - uint32_t
223- if ( ! TryRead ( address , config . IsLittleEndian , reader , out uint descriptorSize ) )
226+ if ( ! TryRead ( address , config . IsLittleEndian , dataTargetDelegates , out uint descriptorSize ) )
224227 return false ;
225228
226229 address += sizeof ( uint ) ;
227230
228231 // Descriptor - char*
229- if ( ! TryReadPointer ( address , config , reader , out TargetPointer descriptorAddr ) )
232+ if ( ! TryReadPointer ( address , config , dataTargetDelegates , out TargetPointer descriptorAddr ) )
230233 return false ;
231234
232235 address += ( uint ) pointerSize ;
233236
234237 // Pointer data count - uint32_t
235- if ( ! TryRead ( address , config . IsLittleEndian , reader , out uint pointerDataCount ) )
238+ if ( ! TryRead ( address , config . IsLittleEndian , dataTargetDelegates , out uint pointerDataCount ) )
236239 return false ;
237240
238241 address += sizeof ( uint ) ;
@@ -241,14 +244,14 @@ private static bool TryReadContractDescriptor(
241244 address += sizeof ( uint ) ;
242245
243246 // Pointer data - uintptr_t*
244- if ( ! TryReadPointer ( address , config , reader , out TargetPointer pointerDataAddr ) )
247+ if ( ! TryReadPointer ( address , config , dataTargetDelegates , out TargetPointer pointerDataAddr ) )
245248 return false ;
246249
247250 // Read descriptor
248251 Span < byte > descriptorBuffer = descriptorSize <= StackAllocByteThreshold
249252 ? stackalloc byte [ ( int ) descriptorSize ]
250253 : new byte [ ( int ) descriptorSize ] ;
251- if ( reader . ReadFromTarget ( descriptorAddr . Value , descriptorBuffer ) < 0 )
254+ if ( dataTargetDelegates . ReadFromTarget ( descriptorAddr . Value , descriptorBuffer ) < 0 )
252255 return false ;
253256
254257 descriptor = ContractDescriptorParser . ParseCompact ( descriptorBuffer ) ;
@@ -259,7 +262,7 @@ private static bool TryReadContractDescriptor(
259262 pointerData = new TargetPointer [ pointerDataCount ] ;
260263 for ( int i = 0 ; i < pointerDataCount ; i ++ )
261264 {
262- if ( ! TryReadPointer ( pointerDataAddr . Value + ( uint ) ( i * pointerSize ) , config , reader , out pointerData [ i ] ) )
265+ if ( ! TryReadPointer ( pointerDataAddr . Value + ( uint ) ( i * pointerSize ) , config , dataTargetDelegates , out pointerData [ i ] ) )
263266 return false ;
264267 }
265268
@@ -280,7 +283,7 @@ private static DataType GetDataType(string type)
280283 public override bool TryGetThreadContext ( ulong threadId , uint contextFlags , Span < byte > buffer )
281284 {
282285 // Underlying API only supports 32-bit thread IDs, mask off top 32 bits
283- int hr = _reader . GetThreadContext ( ( uint ) ( threadId & uint . MaxValue ) , contextFlags , buffer ) ;
286+ int hr = _dataTargetDelegates . GetThreadContext ( ( uint ) ( threadId & uint . MaxValue ) , contextFlags , buffer ) ;
284287 return hr == 0 ;
285288 }
286289
@@ -292,24 +295,50 @@ public override bool TryGetThreadContext(ulong threadId, uint contextFlags, Span
292295 /// <returns>Value read from the target</returns>
293296 public override T Read < T > ( ulong address )
294297 {
295- if ( ! TryRead ( address , _config . IsLittleEndian , _reader , out T value ) )
298+ if ( ! TryRead ( address , _config . IsLittleEndian , _dataTargetDelegates , out T value ) )
296299 throw new InvalidOperationException ( $ "Failed to read { typeof ( T ) } at 0x{ address : x8} .") ;
297300
298301 return value ;
299302 }
300303
301- private static bool TryRead < T > ( ulong address , bool isLittleEndian , Reader reader , out T value ) where T : unmanaged, IBinaryInteger < T > , IMinMaxValue < T >
304+ private static bool TryRead < T > ( ulong address , bool isLittleEndian , DataTargetDelegates dataTargetDelegates , out T value ) where T : unmanaged, IBinaryInteger < T > , IMinMaxValue < T >
302305 {
303306 value = default ;
304307 Span < byte > buffer = stackalloc byte [ sizeof ( T ) ] ;
305- if ( reader . ReadFromTarget ( address , buffer ) < 0 )
308+ if ( dataTargetDelegates . ReadFromTarget ( address , buffer ) < 0 )
306309 return false ;
307310
308311 return isLittleEndian
309312 ? T . TryReadLittleEndian ( buffer , ! IsSigned < T > ( ) , out value )
310313 : T . TryReadBigEndian ( buffer , ! IsSigned < T > ( ) , out value ) ;
311314 }
312315
316+ /// <summary>
317+ /// Write a value to the target in target endianness
318+ /// </summary>
319+ /// <typeparam name="T">Type of value to write</typeparam>
320+ /// <param name="address">Address to start writing to</param>
321+ /// <returns>True if the value is successfully written. Throws an InvalidOperationException otherwise.</returns>
322+ public override bool Write < T > ( ulong address , T value )
323+ {
324+ if ( ! TryWrite ( address , _config . IsLittleEndian , _dataTargetDelegates , value ) )
325+ throw new InvalidOperationException ( $ "Failed to write { typeof ( T ) } at 0x{ address : x8} .") ;
326+ return true ;
327+ }
328+
329+ private static bool TryWrite < T > ( ulong address , bool isLittleEndian , DataTargetDelegates dataTargetDelegates , T value ) where T : unmanaged, IBinaryInteger < T > , IMinMaxValue < T >
330+ {
331+ Span < byte > buffer = stackalloc byte [ sizeof ( T ) ] ;
332+ int bytesWritten = default ;
333+ bool success = isLittleEndian
334+ ? value . TryWriteLittleEndian ( buffer , out bytesWritten )
335+ : value . TryWriteBigEndian ( buffer , out bytesWritten ) ;
336+ if ( ! success || bytesWritten != buffer . Length || dataTargetDelegates . WriteToTarget ( address , buffer ) < 0 )
337+ return false ;
338+
339+ return true ;
340+ }
341+
313342 private static T Read < T > ( ReadOnlySpan < byte > bytes , bool isLittleEndian ) where T : unmanaged, IBinaryInteger < T > , IMinMaxValue < T >
314343 {
315344 if ( sizeof ( T ) != bytes . Length )
@@ -335,7 +364,18 @@ public override void ReadBuffer(ulong address, Span<byte> buffer)
335364
336365 private bool TryReadBuffer ( ulong address , Span < byte > buffer )
337366 {
338- return _reader . ReadFromTarget ( address , buffer ) >= 0 ;
367+ return _dataTargetDelegates . ReadFromTarget ( address , buffer ) >= 0 ;
368+ }
369+
370+ public override void WriteBuffer ( ulong address , Span < byte > buffer )
371+ {
372+ if ( ! TryWriteBuffer ( address , buffer ) )
373+ throw new InvalidOperationException ( $ "Failed to write { buffer . Length } bytes at 0x{ address : x8} .") ;
374+ }
375+
376+ private bool TryWriteBuffer ( ulong address , Span < byte > buffer )
377+ {
378+ return _dataTargetDelegates . WriteToTarget ( address , buffer ) >= 0 ;
339379 }
340380
341381 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
@@ -351,7 +391,7 @@ private static bool IsSigned<T>() where T : struct, INumberBase<T>, IMinMaxValue
351391 /// <returns>Pointer read from the target</returns>}
352392 public override TargetPointer ReadPointer ( ulong address )
353393 {
354- if ( ! TryReadPointer ( address , _config , _reader , out TargetPointer pointer ) )
394+ if ( ! TryReadPointer ( address , _config , _dataTargetDelegates , out TargetPointer pointer ) )
355395 throw new InvalidOperationException ( $ "Failed to read pointer at 0x{ address : x8} .") ;
356396
357397 return pointer ;
@@ -456,33 +496,33 @@ public override string ReadUtf16String(ulong address)
456496 /// <returns>Value read from the target</returns>
457497 public override TargetNUInt ReadNUInt ( ulong address )
458498 {
459- if ( ! TryReadNUInt ( address , _config , _reader , out ulong value ) )
499+ if ( ! TryReadNUInt ( address , _config , _dataTargetDelegates , out ulong value ) )
460500 throw new InvalidOperationException ( $ "Failed to read nuint at 0x{ address : x8} .") ;
461501
462502 return new TargetNUInt ( value ) ;
463503 }
464504
465- private static bool TryReadPointer ( ulong address , Configuration config , Reader reader , out TargetPointer pointer )
505+ private static bool TryReadPointer ( ulong address , Configuration config , DataTargetDelegates dataTargetDelegates , out TargetPointer pointer )
466506 {
467507 pointer = TargetPointer . Null ;
468- if ( ! TryReadNUInt ( address , config , reader , out ulong value ) )
508+ if ( ! TryReadNUInt ( address , config , dataTargetDelegates , out ulong value ) )
469509 return false ;
470510
471511 pointer = new TargetPointer ( value ) ;
472512 return true ;
473513 }
474514
475- private static bool TryReadNUInt ( ulong address , Configuration config , Reader reader , out ulong value )
515+ private static bool TryReadNUInt ( ulong address , Configuration config , DataTargetDelegates dataTargetDelegates , out ulong value )
476516 {
477517 value = 0 ;
478518 if ( config . PointerSize == sizeof ( uint )
479- && TryRead ( address , config . IsLittleEndian , reader , out uint value32 ) )
519+ && TryRead ( address , config . IsLittleEndian , dataTargetDelegates , out uint value32 ) )
480520 {
481521 value = value32 ;
482522 return true ;
483523 }
484524 else if ( config . PointerSize == sizeof ( ulong )
485- && TryRead ( address , config . IsLittleEndian , reader , out ulong value64 ) )
525+ && TryRead ( address , config . IsLittleEndian , dataTargetDelegates , out ulong value64 ) )
486526 {
487527 value = value64 ;
488528 return true ;
@@ -657,8 +697,9 @@ public void Clear()
657697 }
658698 }
659699
660- private readonly struct Reader (
700+ private readonly struct DataTargetDelegates (
661701 ReadFromTargetDelegate readFromTarget ,
702+ WriteToTargetDelegate writeToTarget ,
662703 GetTargetThreadContextDelegate getThreadContext )
663704 {
664705 public int ReadFromTarget ( ulong address , Span < byte > buffer )
@@ -673,5 +714,9 @@ public int GetThreadContext(uint threadId, uint contextFlags, Span<byte> buffer)
673714 {
674715 return getThreadContext ( threadId , contextFlags , buffer ) ;
675716 }
717+ public int WriteToTarget ( ulong address , Span < byte > buffer )
718+ {
719+ return writeToTarget ( address , buffer ) ;
720+ }
676721 }
677722}
0 commit comments