@@ -32,8 +32,8 @@ private readonly struct Configuration
32
32
}
33
33
34
34
private readonly Configuration _config ;
35
- private readonly Reader _reader ;
36
35
36
+ private readonly DataTargetDelegates _dataTargetDelegates ;
37
37
private readonly Dictionary < string , int > _contracts = [ ] ;
38
38
private readonly IReadOnlyDictionary < string , GlobalValue > _globals = new Dictionary < string , GlobalValue > ( ) ;
39
39
private readonly Dictionary < DataType , Target . TypeInfo > _knownTypes = [ ] ;
@@ -43,6 +43,7 @@ private readonly struct Configuration
43
43
public override DataCache ProcessedData { get ; }
44
44
45
45
public delegate int ReadFromTargetDelegate ( ulong address , Span < byte > bufferToFill ) ;
46
+ public delegate int WriteToTargetDelegate ( ulong address , Span < byte > bufferToWrite ) ;
46
47
public delegate int GetTargetThreadContextDelegate ( uint threadId , uint contextFlags , Span < byte > bufferToFill ) ;
47
48
48
49
/// <summary>
@@ -56,18 +57,19 @@ private readonly struct Configuration
56
57
public static bool TryCreate (
57
58
ulong contractDescriptor ,
58
59
ReadFromTargetDelegate readFromTarget ,
60
+ WriteToTargetDelegate writeToTarget ,
59
61
GetTargetThreadContextDelegate getThreadContext ,
60
62
[ NotNullWhen ( true ) ] out ContractDescriptorTarget ? target )
61
63
{
62
- Reader reader = new Reader ( readFromTarget , getThreadContext ) ;
64
+ DataTargetDelegates dataTargetDelegates = new DataTargetDelegates ( readFromTarget , writeToTarget , getThreadContext ) ;
63
65
if ( TryReadContractDescriptor (
64
66
contractDescriptor ,
65
- reader ,
67
+ dataTargetDelegates ,
66
68
out Configuration config ,
67
69
out ContractDescriptorParser . ContractDescriptor ? descriptor ,
68
70
out TargetPointer [ ] pointerData ) )
69
71
{
70
- target = new ContractDescriptorTarget ( config , descriptor ! , pointerData , reader ) ;
72
+ target = new ContractDescriptorTarget ( config , descriptor ! , pointerData , dataTargetDelegates ) ;
71
73
return true ;
72
74
}
73
75
@@ -89,6 +91,7 @@ public static ContractDescriptorTarget Create(
89
91
ContractDescriptorParser . ContractDescriptor contractDescriptor ,
90
92
TargetPointer [ ] globalPointerValues ,
91
93
ReadFromTargetDelegate readFromTarget ,
94
+ WriteToTargetDelegate writeToTarget ,
92
95
GetTargetThreadContextDelegate getThreadContext ,
93
96
bool isLittleEndian ,
94
97
int pointerSize )
@@ -97,15 +100,15 @@ public static ContractDescriptorTarget Create(
97
100
new Configuration { IsLittleEndian = isLittleEndian , PointerSize = pointerSize } ,
98
101
contractDescriptor ,
99
102
globalPointerValues ,
100
- new Reader ( readFromTarget , getThreadContext ) ) ;
103
+ new DataTargetDelegates ( readFromTarget , writeToTarget , getThreadContext ) ) ;
101
104
}
102
105
103
- private ContractDescriptorTarget ( Configuration config , ContractDescriptorParser . ContractDescriptor descriptor , TargetPointer [ ] pointerData , Reader reader )
106
+ private ContractDescriptorTarget ( Configuration config , ContractDescriptorParser . ContractDescriptor descriptor , TargetPointer [ ] pointerData , DataTargetDelegates dataTargetDelegates )
104
107
{
105
108
Contracts = new CachingContractRegistry ( this , this . TryGetContractVersion ) ;
106
109
ProcessedData = new DataCache ( this ) ;
107
110
_config = config ;
108
- _reader = reader ;
111
+ _dataTargetDelegates = dataTargetDelegates ;
109
112
110
113
_contracts = descriptor . Contracts ?? [ ] ;
111
114
@@ -187,7 +190,7 @@ private struct GlobalValue
187
190
// See docs/design/datacontracts/contract-descriptor.md
188
191
private static bool TryReadContractDescriptor (
189
192
ulong address ,
190
- Reader reader ,
193
+ DataTargetDelegates dataTargetDelegates ,
191
194
out Configuration config ,
192
195
out ContractDescriptorParser . ContractDescriptor ? descriptor ,
193
196
out TargetPointer [ ] pointerData )
@@ -198,7 +201,7 @@ private static bool TryReadContractDescriptor(
198
201
199
202
// Magic - uint64_t
200
203
Span < byte > buffer = stackalloc byte [ sizeof ( ulong ) ] ;
201
- if ( reader . ReadFromTarget ( address , buffer ) < 0 )
204
+ if ( dataTargetDelegates . ReadFromTarget ( address , buffer ) < 0 )
202
205
return false ;
203
206
204
207
address += sizeof ( ulong ) ;
@@ -209,7 +212,7 @@ private static bool TryReadContractDescriptor(
209
212
return false ;
210
213
211
214
// Flags - uint32_t
212
- if ( ! TryRead ( address , isLittleEndian , reader , out uint flags ) )
215
+ if ( ! TryRead ( address , isLittleEndian , dataTargetDelegates , out uint flags ) )
213
216
return false ;
214
217
215
218
address += sizeof ( uint ) ;
@@ -220,19 +223,19 @@ private static bool TryReadContractDescriptor(
220
223
config = new Configuration { IsLittleEndian = isLittleEndian , PointerSize = pointerSize } ;
221
224
222
225
// Descriptor size - uint32_t
223
- if ( ! TryRead ( address , config . IsLittleEndian , reader , out uint descriptorSize ) )
226
+ if ( ! TryRead ( address , config . IsLittleEndian , dataTargetDelegates , out uint descriptorSize ) )
224
227
return false ;
225
228
226
229
address += sizeof ( uint ) ;
227
230
228
231
// Descriptor - char*
229
- if ( ! TryReadPointer ( address , config , reader , out TargetPointer descriptorAddr ) )
232
+ if ( ! TryReadPointer ( address , config , dataTargetDelegates , out TargetPointer descriptorAddr ) )
230
233
return false ;
231
234
232
235
address += ( uint ) pointerSize ;
233
236
234
237
// 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 ) )
236
239
return false ;
237
240
238
241
address += sizeof ( uint ) ;
@@ -241,14 +244,14 @@ private static bool TryReadContractDescriptor(
241
244
address += sizeof ( uint ) ;
242
245
243
246
// Pointer data - uintptr_t*
244
- if ( ! TryReadPointer ( address , config , reader , out TargetPointer pointerDataAddr ) )
247
+ if ( ! TryReadPointer ( address , config , dataTargetDelegates , out TargetPointer pointerDataAddr ) )
245
248
return false ;
246
249
247
250
// Read descriptor
248
251
Span < byte > descriptorBuffer = descriptorSize <= StackAllocByteThreshold
249
252
? stackalloc byte [ ( int ) descriptorSize ]
250
253
: new byte [ ( int ) descriptorSize ] ;
251
- if ( reader . ReadFromTarget ( descriptorAddr . Value , descriptorBuffer ) < 0 )
254
+ if ( dataTargetDelegates . ReadFromTarget ( descriptorAddr . Value , descriptorBuffer ) < 0 )
252
255
return false ;
253
256
254
257
descriptor = ContractDescriptorParser . ParseCompact ( descriptorBuffer ) ;
@@ -259,7 +262,7 @@ private static bool TryReadContractDescriptor(
259
262
pointerData = new TargetPointer [ pointerDataCount ] ;
260
263
for ( int i = 0 ; i < pointerDataCount ; i ++ )
261
264
{
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 ] ) )
263
266
return false ;
264
267
}
265
268
@@ -280,7 +283,7 @@ private static DataType GetDataType(string type)
280
283
public override bool TryGetThreadContext ( ulong threadId , uint contextFlags , Span < byte > buffer )
281
284
{
282
285
// 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 ) ;
284
287
return hr == 0 ;
285
288
}
286
289
@@ -292,24 +295,50 @@ public override bool TryGetThreadContext(ulong threadId, uint contextFlags, Span
292
295
/// <returns>Value read from the target</returns>
293
296
public override T Read < T > ( ulong address )
294
297
{
295
- if ( ! TryRead ( address , _config . IsLittleEndian , _reader , out T value ) )
298
+ if ( ! TryRead ( address , _config . IsLittleEndian , _dataTargetDelegates , out T value ) )
296
299
throw new InvalidOperationException ( $ "Failed to read { typeof ( T ) } at 0x{ address : x8} .") ;
297
300
298
301
return value ;
299
302
}
300
303
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 >
302
305
{
303
306
value = default ;
304
307
Span < byte > buffer = stackalloc byte [ sizeof ( T ) ] ;
305
- if ( reader . ReadFromTarget ( address , buffer ) < 0 )
308
+ if ( dataTargetDelegates . ReadFromTarget ( address , buffer ) < 0 )
306
309
return false ;
307
310
308
311
return isLittleEndian
309
312
? T . TryReadLittleEndian ( buffer , ! IsSigned < T > ( ) , out value )
310
313
: T . TryReadBigEndian ( buffer , ! IsSigned < T > ( ) , out value ) ;
311
314
}
312
315
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
+
313
342
private static T Read < T > ( ReadOnlySpan < byte > bytes , bool isLittleEndian ) where T : unmanaged, IBinaryInteger < T > , IMinMaxValue < T >
314
343
{
315
344
if ( sizeof ( T ) != bytes . Length )
@@ -335,7 +364,18 @@ public override void ReadBuffer(ulong address, Span<byte> buffer)
335
364
336
365
private bool TryReadBuffer ( ulong address , Span < byte > buffer )
337
366
{
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 ;
339
379
}
340
380
341
381
[ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
@@ -351,7 +391,7 @@ private static bool IsSigned<T>() where T : struct, INumberBase<T>, IMinMaxValue
351
391
/// <returns>Pointer read from the target</returns>}
352
392
public override TargetPointer ReadPointer ( ulong address )
353
393
{
354
- if ( ! TryReadPointer ( address , _config , _reader , out TargetPointer pointer ) )
394
+ if ( ! TryReadPointer ( address , _config , _dataTargetDelegates , out TargetPointer pointer ) )
355
395
throw new InvalidOperationException ( $ "Failed to read pointer at 0x{ address : x8} .") ;
356
396
357
397
return pointer ;
@@ -456,33 +496,33 @@ public override string ReadUtf16String(ulong address)
456
496
/// <returns>Value read from the target</returns>
457
497
public override TargetNUInt ReadNUInt ( ulong address )
458
498
{
459
- if ( ! TryReadNUInt ( address , _config , _reader , out ulong value ) )
499
+ if ( ! TryReadNUInt ( address , _config , _dataTargetDelegates , out ulong value ) )
460
500
throw new InvalidOperationException ( $ "Failed to read nuint at 0x{ address : x8} .") ;
461
501
462
502
return new TargetNUInt ( value ) ;
463
503
}
464
504
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 )
466
506
{
467
507
pointer = TargetPointer . Null ;
468
- if ( ! TryReadNUInt ( address , config , reader , out ulong value ) )
508
+ if ( ! TryReadNUInt ( address , config , dataTargetDelegates , out ulong value ) )
469
509
return false ;
470
510
471
511
pointer = new TargetPointer ( value ) ;
472
512
return true ;
473
513
}
474
514
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 )
476
516
{
477
517
value = 0 ;
478
518
if ( config . PointerSize == sizeof ( uint )
479
- && TryRead ( address , config . IsLittleEndian , reader , out uint value32 ) )
519
+ && TryRead ( address , config . IsLittleEndian , dataTargetDelegates , out uint value32 ) )
480
520
{
481
521
value = value32 ;
482
522
return true ;
483
523
}
484
524
else if ( config . PointerSize == sizeof ( ulong )
485
- && TryRead ( address , config . IsLittleEndian , reader , out ulong value64 ) )
525
+ && TryRead ( address , config . IsLittleEndian , dataTargetDelegates , out ulong value64 ) )
486
526
{
487
527
value = value64 ;
488
528
return true ;
@@ -657,8 +697,9 @@ public void Clear()
657
697
}
658
698
}
659
699
660
- private readonly struct Reader (
700
+ private readonly struct DataTargetDelegates (
661
701
ReadFromTargetDelegate readFromTarget ,
702
+ WriteToTargetDelegate writeToTarget ,
662
703
GetTargetThreadContextDelegate getThreadContext )
663
704
{
664
705
public int ReadFromTarget ( ulong address , Span < byte > buffer )
@@ -673,5 +714,9 @@ public int GetThreadContext(uint threadId, uint contextFlags, Span<byte> buffer)
673
714
{
674
715
return getThreadContext ( threadId , contextFlags , buffer ) ;
675
716
}
717
+ public int WriteToTarget ( ulong address , Span < byte > buffer )
718
+ {
719
+ return writeToTarget ( address , buffer ) ;
720
+ }
676
721
}
677
722
}
0 commit comments