forked from cseagle/blc
-
Notifications
You must be signed in to change notification settings - Fork 0
/
memstate.cc
735 lines (655 loc) · 25 KB
/
memstate.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
/* ###
* IP: GHIDRA
*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "memstate.hh"
#include "translate.hh"
/// This is a static convenience routine for decoding a value from a sequence of bytes depending
/// on the desired endianness
/// \param ptr is the pointer to the bytes to decode
/// \param size is the number of bytes
/// \param bigendian is \b true if the bytes are encoded in big endian form
/// \return the decoded value
uintb MemoryBank::constructValue(const uint1 *ptr,int4 size,bool bigendian)
{
uintb res = 0;
if (bigendian) {
for(int4 i=0;i<size;++i) {
res <<= 8;
res += (uintb) ptr[i];
}
}
else {
for(int4 i=size-1;i>=0;--i) {
res <<= 8;
res += (uintb) ptr[i];
}
}
return res;
}
/// This is a static convenience routine for encoding bytes from a given value, depending on
/// the desired endianness
/// \param ptr is a pointer to the location to write the encoded bytes
/// \param val is the value to be encoded
/// \param size is the number of bytes to encode
/// \param bigendian is \b true if a big endian encoding is desired
void MemoryBank::deconstructValue(uint1 *ptr,uintb val,int4 size,bool bigendian)
{
if (bigendian) {
for(int4 i=size-1;i>=0;--i) {
ptr[i] = (uint1) (val & 0xff);
val >>= 8;
}
}
else {
for(int4 i=0;i<size;++i) {
ptr[i] = (uint1) (val & 0xff);
val >>= 8;
}
}
}
/// A MemoryBank must be associated with a specific address space, have a preferred or natural
/// \e wordsize and a natural \e pagesize. Both the \e wordsize and \e pagesize must be a power of 2.
/// \param spc is the associated address space
/// \param ws is the number of bytes in the preferred wordsize
/// \param ps is the number of bytes in a page
MemoryBank::MemoryBank(AddrSpace *spc,int4 ws,int4 ps)
{
space = spc;
wordsize = ws;
pagesize = ps;
}
/// This routine only retrieves data from a single \e page in the memory bank. Bytes need not
/// be retrieved from the exact start of a page, but all bytes must come from \e one page.
/// A page is a fixed number of bytes, and the address of a page is always aligned based
/// on that number of bytes. This routine may be overridden for a page based implementation
/// of the MemoryBank. The default implementation retrieves the page as aligned words
/// using the find method.
/// \param addr is the \e aligned offset of the desired page
/// \param res is a pointer to where fetched data should be written
/// \param skip is the offset \e into \e the \e page to get the bytes from
/// \param size is the number of bytes to retrieve
void MemoryBank::getPage(uintb addr,uint1 *res,int4 skip,int4 size) const
{ // Default implementation just iterates using find
// but could be optimized
uintb ptraddr = addr + skip;
uintb endaddr = ptraddr + size;
uintb startalign = ptraddr & ~((uintb)(wordsize-1));
uintb endalign = endaddr & ~((uintb)(wordsize-1));
if ((endaddr & ((uintb)(wordsize-1))) != 0)
endalign += wordsize;
uintb curval;
bool bswap = ((HOST_ENDIAN==1) != space->isBigEndian());
uint1 *ptr;
do {
curval = find(startalign);
if (bswap)
curval = byte_swap(curval,wordsize);
ptr = (uint1 *)&curval;
int4 sz = wordsize;
if (startalign < addr) {
ptr += (addr-startalign);
sz = wordsize - (addr-startalign);
}
if (startalign + wordsize > endaddr)
sz -= (startalign + wordsize -endaddr);
memcpy(res,ptr,sz);
res += sz;
startalign += wordsize;
} while(startalign != endalign);
}
/// This routine writes data only to a single \e page of the memory bank. Bytes need not be
/// written to the exact start of the page, but all bytes must be written to only one page
/// when using this routine. A page is a
/// fixed number of bytes, and the address of a page is always aligned based on this size.
/// This routine may be overridden for a page based implementation of the MemoryBank. The
/// default implementation writes the page as a sequence of aligned words, using the
/// insert method.
/// \param addr is the \e aligned offset of the desired page
/// \param val is a pointer to the bytes to be written into the page
/// \param skip is the offset \e into \e the \e page where bytes will be written
/// \param size is the number of bytes to be written
void MemoryBank::setPage(uintb addr,const uint1 *val,int4 skip,int4 size)
{ // Default implementation just iterates using insert
// but could be optimized
uintb ptraddr = addr + skip;
uintb endaddr = ptraddr + size;
uintb startalign = ptraddr & ~((uintb)(wordsize-1));
uintb endalign = endaddr & ~((uintb)(wordsize-1));
if ((endaddr & ((uintb)(wordsize-1))) != 0)
endalign += wordsize;
uintb curval;
bool bswap = ((HOST_ENDIAN==1) != space->isBigEndian());
uint1 *ptr;
do {
ptr = (uint1 *)&curval;
int4 sz = wordsize;
if (startalign < addr) {
ptr += (addr-startalign);
sz = wordsize - (addr-startalign);
}
if (startalign + wordsize > endaddr)
sz -= (startalign + wordsize - endaddr);
if (sz != wordsize) {
curval = find(startalign); // Part of word is copied from underlying
memcpy(ptr,val,sz); // Rest is taken from -val-
}
else
curval = *((const uintb *)val); // -val- supplies entire word
if (bswap)
curval = byte_swap(curval,wordsize);
insert(startalign,curval);
val += sz;
startalign += wordsize;
} while(startalign != endalign);
}
/// This routine is used to set a single value in the memory bank at an arbitrary address
/// It takes into account the endianness of the associated address space when encoding the
/// value as bytes in the bank. The value is broken up into aligned pieces of \e wordsize and
/// the actual \b write is performed with the insert routine. If only parts of aligned words
/// are written to, then the remaining parts are filled in with the original value, via the
/// find routine.
/// \param offset is the start of the byte range to write
/// \param size is the number of bytes in the range to write
/// \param val is the value to be written
void MemoryBank::setValue(uintb offset,int4 size,uintb val)
{
uintb alignmask = (uintb)(wordsize-1);
uintb ind = offset & (~alignmask);
int4 skip = offset & alignmask;
int4 size1 = wordsize-skip;
int4 size2;
int4 gap;
uintb val1,val2;
if (size > size1) { // We have spill over
size2 = size - size1;
val1 = find(ind);
val2 = find(ind+wordsize);
gap = wordsize - size2;
}
else {
if (size == wordsize) {
insert(ind,val);
return;
}
val1 = find(ind);
val2 = 0;
gap = size1-size;
size1 = size;
size2 = 0;
}
skip = skip * 8; // Convert from byte skip to bit skip
gap = gap * 8; // Convert from byte to bits
if (space->isBigEndian()) {
if (size2 == 0) {
val1 &= ~(calc_mask(size1)<<gap);
val1 |= val << gap;
insert(ind,val1);
}
else {
val1 &= (~((uintb)0)) << 8*size1;
val1 |= val >> 8*size2;
insert(ind,val1);
val2 &= (~((uintb)0)) >> 8*size2;
val2 |= val << gap;
insert(ind+wordsize,val2);
}
}
else {
if (size2 == 0) {
val1 &= ~(calc_mask(size1)<<skip);
val1 |= val << skip;
insert(ind,val1);
}
else {
val1 &= (~((uintb)0)) >> 8*size1;
val1 |= val << skip;
insert(ind,val1);
val2 &= (~((uintb)0)) << 8*size2;
val2 |= val >> 8*size1;
insert(ind+wordsize,val2);
}
}
}
/// This routine gets the value from a range of bytes at an arbitrary address.
/// It takes into account the endianness of the underlying space when decoding the value.
/// The value is constructed by making one or more aligned word queries, using the find method.
/// The desired value may span multiple words and is reconstructed properly.
/// \param offset is the start of the byte range encoding the value
/// \param size is the number of bytes in the range
/// \return the decoded value
uintb MemoryBank::getValue(uintb offset,int4 size) const
{
uintb res;
uintb alignmask = (uintb) (wordsize-1);
uintb ind = offset & (~alignmask);
int4 skip = offset & alignmask;
int4 size1 = wordsize-skip;
int4 size2;
int4 gap;
uintb val1,val2;
if (size > size1) { // We have spill over
size2 = size - size1;
val1 = find(ind);
val2 = find(ind+wordsize);
gap = wordsize - size2;
}
else {
val1 = find(ind);
val2 = 0;
if (size == wordsize)
return val1;
gap = size1-size;
size1 = size;
size2 = 0;
}
if (space->isBigEndian()) {
if (size2 == 0)
res = val1>>(8*gap);
else
res = (val1<<(8*size2)) | (val2 >> (8*gap));
}
else {
if (size2 == 0)
res = val1 >> (skip*8);
else
res = (val1>>(skip*8)) | (val2<<(size1*8) );
}
res &= (uintb)calc_mask(size);
return res;
}
/// This the most general method for writing a sequence of bytes into the memory bank.
/// There is no restriction on the offset to write to or the number of bytes to be written,
/// except that the range must be contained in the address space.
/// \param offset is the start of the byte range to be written
/// \param size is the number of bytes to write
/// \param val is a pointer to the sequence of bytes to be written into the bank
void MemoryBank::setChunk(uintb offset,int4 size,const uint1 *val)
{
int4 cursize;
int4 count;
uintb pagemask = (uintb) (pagesize - 1);
uintb offalign;
int4 skip;
count = 0;
while(count < size) {
cursize = pagesize;
offalign = offset & ~pagemask;
skip = 0;
if (offalign != offset) {
skip = offset - offalign;
cursize -= skip;
}
if (size - count < cursize)
cursize = size - count;
setPage(offalign,val,skip,cursize);
count += cursize;
offset += cursize;
val += cursize;
}
}
/// This is the most general method for reading a sequence of bytes from the memory bank.
/// There is no restriction on the offset or the number of bytes to read, except that the
/// range must be contained in the address space.
/// \param offset is the start of the byte range to read
/// \param size is the number of bytes to read
/// \param res is a pointer to where the retrieved bytes should be stored
void MemoryBank::getChunk(uintb offset,int4 size,uint1 *res) const
{
int4 cursize,count;
uintb pagemask = (uintb) (pagesize-1);
uintb offalign;
int4 skip;
count = 0;
while(count < size) {
cursize = pagesize;
offalign = offset & ~pagemask;
skip = 0;
if (offalign != offset) {
skip = offset-offalign;
cursize -= skip;
}
if (size - count < cursize)
cursize = size - count;
getPage(offalign,res,skip,cursize);
count += cursize;
offset += cursize;
res += cursize;
}
}
/// Find an aligned word from the bank. First an attempt is made to fetch the data from the
/// LoadImage. If this fails, the value is returned as 0.
/// \param addr is the address of the word to fetch
/// \return the fetched value
uintb MemoryImage::find(uintb addr) const
{ // Assume that -addr- is word aligned
uintb res = 0; // Make sure all bytes start as 0, as load may not fill all bytes
AddrSpace *spc = getSpace();
try {
uint1 *ptr = (uint1 *)&res;
ptr += (HOST_ENDIAN==1) ? (sizeof(uintb) - getWordSize()) : 0;
loader->loadFill(ptr,getWordSize(),Address(spc,addr));
} catch(DataUnavailError &err) {
// Pages not mapped in the load image, are assumed to be zero
res = 0;
}
if ((HOST_ENDIAN==1) != spc->isBigEndian())
res = byte_swap(res,getWordSize());
return res;
}
/// Retrieve an aligned page from the bank. First an attempt is made to retrieve the
/// page from the LoadImage, which may do its own zero filling. If the attempt fails, the
/// page is entirely filled in with zeros.
void MemoryImage::getPage(uintb addr,uint1 *res,int4 skip,int4 size) const
{ // Assume that -addr- is page aligned
AddrSpace *spc = getSpace();
try {
loader->loadFill(res,size,Address(spc,addr+skip));
}
catch(DataUnavailError &err) {
// Pages not mapped in the load image, are assumed to be zero
for(int4 i=0;i<size;++i)
res[i] = 0;
}
}
/// A MemoryImage needs everything a basic memory bank needs and is needs to know
/// the underlying LoadImage object to forward read reqests to.
/// \param spc is the address space associated with the memory bank
/// \param ws is the number of bytes in the preferred wordsize (must be power of 2)
/// \param ps is the number of bytes in a page (must be power of 2)
/// \param ld is the underlying LoadImage
MemoryImage::MemoryImage(AddrSpace *spc,int4 ws,int4 ps,LoadImage *ld)
: MemoryBank(spc,ws,ps)
{
loader = ld;
}
/// This derived method looks for a previously cached page of the underlying memory bank.
/// If the cached page does not exist, it creates it and fills in its initial value by
/// retrieving the page from the underlying bank. The new value is then written into
/// cached page.
/// \param addr is the aligned address of the word to be written
/// \param val is the value to be written at that word
void MemoryPageOverlay::insert(uintb addr,uintb val)
{
uintb pageaddr = addr & ~((uintb)(getPageSize()-1));
map<uintb,uint1 *>::iterator iter;
uint1 *pageptr;
iter = page.find(pageaddr);
if (iter != page.end())
pageptr = (*iter).second;
else {
pageptr = new uint1[getPageSize()];
page[pageaddr] = pageptr;
if (underlie == (MemoryBank *)0) {
for(int4 i=0;i<getPageSize();++i)
pageptr[i] = 0;
}
else
underlie->getPage(pageaddr,pageptr,0,getPageSize());
}
uintb pageoffset = addr & ((uintb)(getPageSize()-1));
deconstructValue(pageptr + pageoffset,val,getWordSize(),getSpace()->isBigEndian());
}
/// This derived method first looks for the aligned word in the mapped pages. If the
/// address is not mapped, the search is forwarded to the \e underlying memory bank.
/// If there is no underlying bank, zero is returned.
/// \param addr is the aligned offset of the word
/// \return the retrieved value
uintb MemoryPageOverlay::find(uintb addr) const
{
uintb pageaddr = addr & ~((uintb)(getPageSize()-1));
map<uintb,uint1 *>::const_iterator iter;
iter = page.find(pageaddr);
if (iter == page.end()) {
if (underlie == (MemoryBank *)0)
return (uintb)0;
return underlie->find(addr);
}
const uint1 *pageptr = (*iter).second;
uintb pageoffset = addr & ((uintb)(getPageSize()-1));
return constructValue(pageptr+pageoffset,getWordSize(),getSpace()->isBigEndian());
}
/// The desired page is looked for in the page cache. If it doesn't exist, the
/// request is forwarded to \e underlying bank. If there is no underlying bank, the
/// result buffer is filled with zeros.
/// \param addr is the aligned offset of the page
/// \param res is the pointer to where retrieved bytes should be stored
/// \param skip is the offset \e into \e the \e page from where bytes should be retrieved
/// \param size is the number of bytes to retrieve
void MemoryPageOverlay::getPage(uintb addr,uint1 *res,int4 skip,int4 size) const
{
map<uintb,uint1 *>::const_iterator iter;
iter = page.find(addr);
if (iter == page.end()) {
if (underlie == (MemoryBank *)0) {
for(int4 i=0;i<size;++i)
res[i] = 0;
return;
}
underlie->getPage(addr,res,skip,size);
return;
}
const uint1 *pageptr = (*iter).second;
memcpy(res,pageptr+skip,size);
}
/// First, a cached version of the desired page is searched for via its address. If it doesn't
/// exist, it is created, and its initial value is filled via the \e underlying bank. The bytes
/// to be written are then copied into the cached page.
/// \param addr is the aligned offset of the page to write
/// \param val is a pointer to bytes to be written into the page
/// \param skip is the offset \e into \e the \e page where bytes should be written
/// \param size is the number of bytes to write
void MemoryPageOverlay::setPage(uintb addr,const uint1 *val,int4 skip,int4 size)
{
map<uintb,uint1 *>::iterator iter;
uint1 *pageptr;
iter = page.find(addr);
if (iter == page.end()) {
pageptr = new uint1[getPageSize()];
page[addr] = pageptr;
if (size != getPageSize()) {
if (underlie == (MemoryBank *)0) {
for(int4 i=0;i<getPageSize();++i)
pageptr[i] = 0;
}
else
underlie->getPage(addr,pageptr,0,getPageSize());
}
}
else
pageptr = (*iter).second;
memcpy(pageptr+skip,val,size);
}
/// A page overlay memory bank needs all the parameters for a generic memory bank
/// and it needs to know the underlying memory bank being overlayed.
/// \param spc is the address space associated with the memory bank
/// \param ws is the number of bytes in the preferred wordsize (must be power of 2)
/// \param ps is the number of bytes in a page (must be power of 2)
/// \param ul is the underlying MemoryBank
MemoryPageOverlay::MemoryPageOverlay(AddrSpace *spc,int4 ws,int4 ps,MemoryBank *ul)
: MemoryBank(spc,ws,ps)
{
underlie = ul;
}
MemoryPageOverlay::~MemoryPageOverlay(void)
{
map<uintb,uint1 *>::iterator iter;
for(iter=page.begin();iter!=page.end();++iter)
delete [] (*iter).second;
}
/// Write the value into the hashtable, using \b addr as a key.
/// \param addr is the aligned address of the word being written
/// \param val is the value of the word to write
void MemoryHashOverlay::insert(uintb addr,uintb val)
{
int4 size = address.size();
uintb offset = (addr>>alignshift) % size;
for(int4 i=0;i<size;++i) {
if (address[offset] == addr) { // Address has been seen before
value[offset] = val; // Replace old value
return;
}
else if (address[offset] == (uintb)0xBADBEEF) { // Address not seen before
address[offset] = addr; // Claim this hash slot
value[offset] = val; // Set value
return;
}
offset = (offset + collideskip) % size;
}
throw LowlevelError("Memory state hash_table is full");
}
/// First search for an entry in the hashtable using \b addr as a key. If there is no
/// entry, forward the query to the underlying memory bank, or return 0 if there is no underlying bank
/// \param addr is the aligned address of the word to retrieve
/// \return the retrieved value
uintb MemoryHashOverlay::find(uintb addr) const
{ // Find address in hash-table, or return find from underlying memory
int4 size = address.size();
uintb offset = (addr>>alignshift) % size;
for(int4 i=0;i<size;++i) {
if (address[offset] == addr) // Address has been seen before
return value[offset];
else if (address[offset] == 0xBADBEEF) // Address not seen before
break;
offset = (offset + collideskip) % size;
}
// We didn't find the address in the hashtable
if (underlie == (MemoryBank *)0)
return (uintb)0;
return underlie->find(addr);
}
/// A MemoryBank implemented as a hash table needs everything associated with a generic
/// memory bank, but the constructor also needs to know the size of the hashtable and
/// the underlying memorybank to forward reads and writes to.
/// \param spc is the address space associated with the memory bank
/// \param ws is the number of bytes in the preferred wordsize (must be power of 2)
/// \param ps is the number of bytes in a page (must be a power of 2)
/// \param hashsize is the maximum number of entries in the hashtable
/// \param ul is the underlying memory bank being overlayed
MemoryHashOverlay::MemoryHashOverlay(AddrSpace *spc,int4 ws,int4 ps,int4 hashsize,MemoryBank *ul)
: MemoryBank(spc,ws,ps), address(hashsize,0xBADBEEF), value(hashsize,0)
{
underlie = ul;
collideskip = 1023;
uint4 tmp = ws - 1;
alignshift = 0;
while(tmp != 0) {
alignshift += 1;
tmp >>= 1;
}
}
/// MemoryBanks associated with specific address spaces must be registers with this MemoryState
/// via this method. Each address space that will be used during emulation must be registered
/// separately. The MemoryState object does \e not assume responsibility for freeing the MemoryBank
/// \param bank is a pointer to the MemoryBank to be registered
void MemoryState::setMemoryBank(MemoryBank *bank)
{
AddrSpace *spc = bank->getSpace();
int4 index = spc->getIndex();
while(index >= memspace.size())
memspace.push_back((MemoryBank *)0);
memspace[index] = bank;
}
/// Any MemoryBank that has been registered with this MemoryState can be retrieved via this
/// method if the MemoryBank's associated address space is known.
/// \param spc is the address space of the desired MemoryBank
/// \return a pointer to the MemoryBank or \b null if no bank is associated with \e spc.
MemoryBank *MemoryState::getMemoryBank(AddrSpace *spc) const
{
int4 index = spc->getIndex();
if (index >= memspace.size())
return (MemoryBank *)0;
return memspace[index];
}
/// This is the main interface for writing values to the MemoryState.
/// If there is no registered MemoryBank for the desired address space, or
/// if there is some other error, an exception is thrown.
/// \param spc is the address space to write to
/// \param off is the offset where the value should be written
/// \param size is the number of bytes to be written
/// \param cval is the value to be written
void MemoryState::setValue(AddrSpace *spc,uintb off,int4 size,uintb cval)
{
MemoryBank *mspace = getMemoryBank(spc);
if (mspace == (MemoryBank *)0)
throw LowlevelError("Setting value for unmapped memory space: "+spc->getName());
mspace->setValue(off,size,cval);
}
/// This is the main interface for reading values from the MemoryState.
/// If there is no registered MemoryBank for the desired address space, or
/// if there is some other error, an exception is thrown.
/// \param spc is the address space being queried
/// \param off is the offset of the value being queried
/// \param size is the number of bytes to query
/// \return the queried value
uintb MemoryState::getValue(AddrSpace *spc,uintb off,int4 size) const
{
if (spc->getType() == IPTR_CONSTANT) return off;
MemoryBank *mspace = getMemoryBank(spc);
if (mspace == (MemoryBank *)0)
throw LowlevelError("Getting value from unmapped memory space: "+spc->getName());
return mspace->getValue(off,size);
}
/// This is a convenience method for setting registers by name.
/// Any register name known to the Translate object can be used as a write location.
/// The associated address space, offset, and size is looked up and automatically
/// passed to the main setValue routine.
/// \param nm is the name of the register
/// \param cval is the value to write to the register
void MemoryState::setValue(const string &nm,uintb cval)
{ // Set a "register" value
const VarnodeData &vdata( trans->getRegister(nm) );
setValue(vdata.space,vdata.offset,vdata.size,cval);
}
/// This is a convenience method for reading registers by name.
/// Any register name known to the Translate object can be used as a read location.
/// The associated address space, offset, and size is looked up and automatically
/// passed to the main getValue routine.
/// \param nm is the name of the register
/// \return the value associated with that register
uintb MemoryState::getValue(const string &nm) const
{ // Get a "register" value
const VarnodeData &vdata( trans->getRegister(nm) );
return getValue(vdata.space,vdata.offset,vdata.size);
}
/// This is the main interface for reading a range of bytes from the MemorySate.
/// The MemoryBank associated with the address space of the query is looked up
/// and the request is forwarded to the getChunk method on the MemoryBank. If there
/// is no registered MemoryBank or some other error, an exception is thrown
/// \param res is a pointer to the result buffer for storing retrieved bytes
/// \param spc is the desired address space
/// \param off is the starting offset of the byte range being queried
/// \param size is the number of bytes being queried
void MemoryState::getChunk(uint1 *res,AddrSpace *spc,uintb off,int4 size) const
{
MemoryBank *mspace = getMemoryBank(spc);
if (mspace == (MemoryBank *)0)
throw LowlevelError("Getting chunk from unmapped memory space: "+spc->getName());
mspace->getChunk(off,size,res);
}
/// This is the main interface for setting values for a range of bytes in the MemoryState.
/// The MemoryBank associated with the desired address space is looked up and the
/// write is forwarded to the setChunk method on the MemoryBank. If there is no
/// registered MemoryBank or some other error, an exception is throw.
/// \param val is a pointer to the byte values to be written into the MemoryState
/// \param spc is the address space being written
/// \param off is the starting offset of the range being written
/// \param size is the number of bytes to write
void MemoryState::setChunk(const uint1 *val,AddrSpace *spc,uintb off,int4 size)
{
MemoryBank *mspace = getMemoryBank(spc);
if (mspace == (MemoryBank *)0)
throw LowlevelError("Setting chunk of unmapped memory space: "+spc->getName());
mspace->setChunk(off,size,val);
}