-
Notifications
You must be signed in to change notification settings - Fork 50
/
double.cc
3553 lines (3247 loc) · 114 KB
/
double.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
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/* ###
* 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 "double.hh"
namespace ghidra {
/// Internally, the \b lo and \b hi Varnodes are set to null, and the \b val field
/// holds the constant value.
/// \param sz is the size in bytes of the constant
/// \param v is the constant value
SplitVarnode::SplitVarnode(int4 sz,uintb v)
{
val = v;
wholesize = sz;
lo = (Varnode *)0;
hi = (Varnode *)0;
whole = (Varnode *)0;
defpoint = (PcodeOp *)0;
defblock = (BlockBasic *)0;
}
/// \param sz is the size of the constant in bytes
/// \param v is the constant value
void SplitVarnode::initPartial(int4 sz,uintb v)
{
val = v;
wholesize = sz;
lo = (Varnode *)0;
hi = (Varnode *)0;
whole = (Varnode *)0;
defpoint = (PcodeOp *)0;
defblock = (BlockBasic *)0;
}
/// The Varnode pieces can be constant, in which case a constant SplitVarnode is initialized and
/// a constant value is built from the pieces. The given most significant piece can be null, indicating
/// that the most significant piece of the whole is an implied zero.
/// \param sz is the size of the logical whole in bytes
/// \param l is the given (least significant) Varnode piece
/// \param h is the given (most significant) Varnode piece
void SplitVarnode::initPartial(int4 sz,Varnode *l,Varnode *h)
{
if (h == (Varnode *)0) { // hi is an implied zero
hi = (Varnode *)0;
if (l->isConstant()) {
val = l->getOffset(); // Assume l is a constant
lo = (Varnode *)0;
}
else
lo = l;
}
else {
if (l->isConstant() && h->isConstant()) {
val = h->getOffset();
val <<= (l->getSize()*8);
val |= l->getOffset();
lo = (Varnode *)0;
hi = (Varnode *)0;
}
else {
lo = l;
hi = h;
}
}
wholesize = sz;
whole = (Varnode *)0;
defpoint = (PcodeOp *)0;
defblock = (BlockBasic *)0;
}
/// The \b lo, \b hi, and \b whole fields are filled in. The definition point remains uninitialized.
/// \param w is the given whole Varnode
/// \param l is the given (least significant) Varnode piece
/// \param h is the given (most significant) Varnode piece
void SplitVarnode::initAll(Varnode *w,Varnode *l,Varnode *h)
{
wholesize = w->getSize();
lo = l;
hi = h;
whole = w;
defpoint = (PcodeOp *)0;
defblock = (BlockBasic *)0;
}
/// Verify that the given most significant piece is formed via CPUI_SUBPIECE and search
/// for the least significant piece being formed as a CPUI_SUBPIECE of the same whole.
/// \param h is the given (most significant) Varnode piece
/// \return \b true if the matching \b whole and least significant piece is found
bool SplitVarnode::inHandHi(Varnode *h)
{
if (!h->isPrecisHi()) return false; // Check for mark, in order to have quick -false- in most cases
// Search for the companion
if (h->isWritten()) {
PcodeOp *op = h->getDef();
// We could check for double loads here
if (op->code() == CPUI_SUBPIECE) {
Varnode *w = op->getIn(0);
if (op->getIn(1)->getOffset() != (uintb)(w->getSize()-h->getSize())) return false;
list<PcodeOp *>::const_iterator iter,enditer;
iter = w->beginDescend();
enditer = w->endDescend();
while(iter != enditer) {
PcodeOp *tmpop = *iter;
++iter;
if (tmpop->code() != CPUI_SUBPIECE) continue;
Varnode *tmplo = tmpop->getOut();
if (!tmplo->isPrecisLo()) continue;
if (tmplo->getSize() + h->getSize() != w->getSize()) continue;
if (tmpop->getIn(1)->getOffset() != 0) continue;
// There could conceivably be more than one, but this shouldn't happen with CSE
initAll(w,tmplo,h);
return true;
}
}
}
return false;
}
/// Verify that the given least significant piece is formed via CPUI_SUBPIECE and search
/// for the most significant piece being formed as a CPUI_SUBPIECE of the same whole.
/// \param l is the given (least significant) Varnode piece
/// \return \b true if the matching \b whole and most significant piece is found
bool SplitVarnode::inHandLo(Varnode *l)
{
if (!l->isPrecisLo()) return false; // Check for mark, in order to have quick -false- in most cases
// Search for the companion
if (l->isWritten()) {
PcodeOp *op = l->getDef();
// We could check for double loads here
if (op->code() == CPUI_SUBPIECE) {
Varnode *w = op->getIn(0);
if (op->getIn(1)->getOffset() != 0) return false;
list<PcodeOp *>::const_iterator iter,enditer;
iter = w->beginDescend();
enditer = w->endDescend();
while(iter != enditer) {
PcodeOp *tmpop = *iter;
++iter;
if (tmpop->code() != CPUI_SUBPIECE) continue;
Varnode *tmphi = tmpop->getOut();
if (!tmphi->isPrecisHi()) continue;
if (tmphi->getSize() + l->getSize() != w->getSize()) continue;
if (tmpop->getIn(1)->getOffset() != (uintb)l->getSize()) continue;
// There could conceivably be more than one, but this shouldn't happen with CSE
initAll(w,l,tmphi);
return true;
}
}
}
return false;
}
/// The given least significant Varnode must already be marked as a piece.
/// Initialize the SplitVarnode with the given piece and the \b whole that it came from.
/// If a matching most significant piece can be found, as another CPUI_SUBPIECE off of the same
/// \b whole, initialize that as well. Otherwise leave the most significant piece as null.
/// \param l is the given (least significant) Varnode piece
/// \return \b true if the SplitVarnode is successfully initialized
bool SplitVarnode::inHandLoNoHi(Varnode *l)
{
if (!l->isPrecisLo()) return false;
if (!l->isWritten()) return false;
PcodeOp *op = l->getDef();
if (op->code() != CPUI_SUBPIECE) return false;
if (op->getIn(1)->getOffset() != 0) return false;
Varnode *w = op->getIn(0);
list<PcodeOp *>::const_iterator iter,enditer;
iter = w->beginDescend();
enditer = w->endDescend();
while(iter != enditer) {
PcodeOp *tmpop = *iter;
++iter;
if (tmpop->code() != CPUI_SUBPIECE) continue;
Varnode *tmphi = tmpop->getOut();
if (!tmphi->isPrecisHi()) continue;
if (tmphi->getSize() + l->getSize() != w->getSize()) continue;
if (tmpop->getIn(1)->getOffset() != (uintb)l->getSize()) continue;
// There could conceivably be more than one, but this shouldn't happen with CSE
initAll(w,l,tmphi);
return true;
}
initAll(w,l,(Varnode *)0);
return true;
}
/// Initialize the SplitVarnode given the most significant piece, if it is concatenated together
/// immediately with is least significant piece. The CPUI_PIECE and the matching least significant
/// piece must be unique. If these are found, \b hi, \b lo, and \b whole are all filled in.
/// \param h is the given (most significant) piece
/// \return \b true if initialization was successful and the least significant piece was found
bool SplitVarnode::inHandHiOut(Varnode *h)
{
list<PcodeOp *>::const_iterator iter,enditer;
iter = h->beginDescend();
enditer = h->endDescend();
Varnode *loTmp = (Varnode *)0;
Varnode *outvn = (Varnode *)0;
while(iter != enditer) {
PcodeOp *pieceop = *iter;
++iter;
if (pieceop->code() != CPUI_PIECE) continue;
if (pieceop->getIn(0) != h) continue;
Varnode *l = pieceop->getIn(1);
if (!l->isPrecisLo()) continue;
if (loTmp != (Varnode *)0) return false; // Whole is not unique
loTmp = l;
outvn = pieceop->getOut();
}
if (loTmp != (Varnode *)0) {
initAll(outvn,loTmp,h);
return true;
}
return false;
}
/// Initialize the SplitVarnode given the least significant piece, if it is concatenated together
/// immediately with is nost significant piece. The CPUI_PIECE and the matching most significant
/// piece must be unique. If these are found, \b hi, \b lo, and \b whole are all filled in.
/// \param l is the given (least significant) piece
/// \return \b true if initialization was successful and the most significant piece was found
bool SplitVarnode::inHandLoOut(Varnode *l)
{
list<PcodeOp *>::const_iterator iter,enditer;
iter = l->beginDescend();
enditer = l->endDescend();
Varnode *hiTmp = (Varnode *)0;
Varnode *outvn = (Varnode *)0;
while(iter != enditer) {
PcodeOp *pieceop = *iter;
++iter;
if (pieceop->code() != CPUI_PIECE) continue;
if (pieceop->getIn(1) != l) continue;
Varnode *h = pieceop->getIn(0);
if (!h->isPrecisHi()) continue;
if (hiTmp != (Varnode *)0) return false; // Whole is not unique
hiTmp = h;
outvn = pieceop->getOut();
}
if (hiTmp != (Varnode *)0) {
initAll(outvn,l,hiTmp);
return true;
}
return false;
}
/// Look for CPUI_SUBPIECE operations off of a common Varnode.
/// The \b whole field is set to this Varnode if found; the definition point and block are
/// filled in and \b true is returned. Otherwise \b false is returned.
/// \return \b true if the \b whole Varnode is found
bool SplitVarnode::findWholeSplitToPieces(void)
{
if (whole == (Varnode*)0) {
if (hi == (Varnode*)0) return false;
if (lo == (Varnode*)0) return false;
if (!hi->isWritten()) return false;
PcodeOp *subhi = hi->getDef();
if (subhi->code() == CPUI_COPY) { // Go thru one level of copy, if the piece is addrtied
Varnode *otherhi = subhi->getIn(0);
if (!otherhi->isWritten()) return false;
subhi = otherhi->getDef();
}
if (subhi->code() != CPUI_SUBPIECE) return false;
if (subhi->getIn(1)->getOffset() != wholesize - hi->getSize()) return false;
Varnode *putativeWhole = subhi->getIn(0);
if (putativeWhole->getSize() != wholesize) return false;
if (!lo->isWritten()) return false;
PcodeOp *sublo = lo->getDef();
if (sublo->code() == CPUI_COPY) { // Go thru one level of copy, if the piece is addrtied
Varnode *otherlo = sublo->getIn(0);
if (!otherlo->isWritten()) return false;
sublo = otherlo->getDef();
}
if (sublo->code() != CPUI_SUBPIECE) return false;
if (putativeWhole != sublo->getIn(0))
return false; // Doesn't match between pieces
if (sublo->getIn(1)->getOffset() != 0)
return false;
whole = putativeWhole;
}
if (whole->isWritten()) {
defpoint = whole->getDef();
defblock = defpoint->getParent();
}
else if (whole->isInput()) {
defpoint = (PcodeOp *)0;
defblock = (BlockBasic *)0;
}
return true;
}
/// Set the basic block, \b defblock, and PcodeOp, \b defpoint, where they are defined.
/// Its possible that \b lo and \b hi are \e input Varnodes with no natural defining PcodeOp,
/// in which case \b defpoint is set to null and \b defblock is set to the function entry block.
/// The method returns \b true, if the definition point is found, which amounts to returning
/// \b false if the SplitVarnode is only half constant or half input.
/// \return \b true if the definition point is located
bool SplitVarnode::findDefinitionPoint(void)
{
PcodeOp *lastop;
if (hi != (Varnode *)0 && hi->isConstant()) return false; // If one but not both is constant
if (lo->isConstant()) return false;
if (hi == (Varnode *)0) { // Implied zero extension
if (lo->isInput()) {
defblock = (BlockBasic *)0;
defpoint = (PcodeOp *)0;
}
else if (lo->isWritten()) {
defpoint = lo->getDef();
defblock = defpoint->getParent();
}
else
return false;
}
else if (hi->isWritten()) {
if (!lo->isWritten()) return false; // Do not allow mixed input/non-input pairs
lastop = hi->getDef();
defblock = lastop->getParent();
PcodeOp *lastop2 = lo->getDef();
BlockBasic *otherblock = lastop2->getParent();
if (defblock != otherblock) {
defpoint = lastop;
FlowBlock *curbl = defblock;
while(curbl != (FlowBlock *)0) { // Make sure defblock dominated by otherblock
curbl = curbl->getImmedDom();
if (curbl == otherblock) return true;
}
defblock = otherblock; // Try lo as final defining location
otherblock = lastop->getParent();
defpoint = lastop2;
curbl = defblock;
while(curbl != (FlowBlock *)0) {
curbl = curbl->getImmedDom();
if (curbl == otherblock) return true;
}
defblock = (BlockBasic *)0;
return false; // Not defined in same basic block
}
if (lastop2->getSeqNum().getOrder() > lastop->getSeqNum().getOrder())
lastop = lastop2;
defpoint = lastop;
}
else if (hi->isInput()) {
if (!lo->isInput())
return false; // Do not allow mixed input/non-input pairs
defblock = (BlockBasic *)0;
defpoint = (PcodeOp *)0;
}
return true;
}
/// If both \b lo and \b hi pieces are written, the earlier of the two defining PcodeOps
/// is returned. Otherwise null is returned.
/// \return the earlier of the two defining PcodeOps or null
PcodeOp *SplitVarnode::findEarliestSplitPoint(void)
{
if (!hi->isWritten()) return (PcodeOp *)0;
if (!lo->isWritten()) return (PcodeOp *)0;
PcodeOp *hiop = hi->getDef();
PcodeOp *loop = lo->getDef();
if (loop->getParent() != hiop->getParent())
return (PcodeOp *)0;
return (loop->getSeqNum().getOrder() < hiop->getSeqNum().getOrder()) ? loop : hiop;
}
/// We scan for concatenations formed out of \b hi and \b lo, in the correct significance order.
/// We assume \b hi and \b lo are defined in the same basic block (or are both inputs) and that
/// the concatenation is also in this block. If such a concatenation is found, \b whole is set to the
/// concatenated Varnode, the defining block and PcodeOp is filled in, and \b true is returned.
/// \return \b true if a \b whole concatenated from \b hi and \b lo is found
bool SplitVarnode::findWholeBuiltFromPieces(void)
{
if (hi==(Varnode *)0) return false;
if (lo==(Varnode *)0) return false;
list<PcodeOp *>::const_iterator iter,enditer;
iter = lo->beginDescend();
enditer = lo->endDescend();
PcodeOp *res = (PcodeOp *)0;
BlockBasic *bb;
if (lo->isWritten())
bb = lo->getDef()->getParent();
else if (lo->isInput())
bb = (BlockBasic *)0;
else
throw LowlevelError("Trying to find whole on free varnode");
while(iter != enditer) {
PcodeOp *op = *iter;
++iter;
if (op->code() != CPUI_PIECE) continue;
if (op->getIn(0) != hi) continue;
if (bb != (BlockBasic *)0) {
if (op->getParent() != bb) continue; // Not defined in earliest block
}
else if (!op->getParent()->isEntryPoint())
continue;
if (res == (PcodeOp *)0)
res = op;
else {
if (op->getSeqNum().getOrder() < res->getSeqNum().getOrder()) // Find "earliest" whole
res = op;
}
}
if (res == (PcodeOp *)0)
whole = (Varnode *)0;
else {
defpoint = res;
defblock = defpoint->getParent();
whole = res->getOut();
}
return (whole!=(Varnode *)0);
}
/// The whole Varnode must be defined or definable \e before the given PcodeOp.
/// This is checked by comparing the given PcodeOp to the defining PcodeOp and block for \b this,
/// which are filled in if they weren't before.
/// \param existop is the given PcodeOp
/// \return \b true if a whole Varnode exists or can be defined before the given PcodeOp
bool SplitVarnode::isWholeFeasible(PcodeOp *existop)
{
if (isConstant()) return true;
if ((lo!=(Varnode *)0)&&(hi!=(Varnode *)0))
if (lo->isConstant() != hi->isConstant()) return false; // Mixed constant/non-constant
if (!findWholeSplitToPieces()) {
if (!findWholeBuiltFromPieces()) {
if (!findDefinitionPoint())
return false;
}
}
if (defblock == (BlockBasic *)0) return true;
FlowBlock *curbl = existop->getParent();
if (curbl == defblock) // If defined in same block as -existop- check PcodeOp ordering
return (defpoint->getSeqNum().getOrder() <= existop->getSeqNum().getOrder());
while(curbl != (FlowBlock *)0) { // Make sure defbock dominates block containing -existop-
curbl = curbl->getImmedDom();
if (curbl == defblock) return true;
}
return false;
}
/// This is similar to isWholeFeasible(), but the \b whole must be defined before the end of the given
/// basic block.
/// \param bl is the given basic block
/// \return \b true if a whole Varnode exists or can be defined before the end of the given basic block
bool SplitVarnode::isWholePhiFeasible(FlowBlock *bl)
{
if (isConstant()) return false;
if (!findWholeSplitToPieces()) {
if (!findWholeBuiltFromPieces()) {
if (!findDefinitionPoint())
return false;
}
}
if (defblock == (BlockBasic *)0) return true;
if (bl == defblock) // If defined in same block
return true;
while(bl != (FlowBlock *)0) { // Make sure defblock dominates block containing -existop-
bl = bl->getImmedDom();
if (bl == defblock) return true;
}
return false;
}
/// This method assumes isWholeFeasible has been called and returned \b true.
/// If the \b whole didn't already exist, it is created as the concatenation of its two pieces.
/// If the pieces were constant, a constant whole Varnode is created.
/// If the \b hi piece was null, the whole is created as a CPUI_ZEXT of the \b lo.
/// \param data is the function owning the Varnode pieces
void SplitVarnode::findCreateWhole(Funcdata &data)
{
if (isConstant()) {
whole = data.newConstant(wholesize,val);
return;
}
else {
if (lo != (Varnode *)0)
lo->setPrecisLo(); // Mark the pieces
if (hi != (Varnode *)0)
hi->setPrecisHi();
}
if (whole != (Varnode *)0) return; // Already found the whole
PcodeOp *concatop;
Address addr;
BlockBasic *topblock = (BlockBasic *)0;
if (defblock != (BlockBasic *)0)
addr = defpoint->getAddr();
else {
topblock = (BlockBasic *)data.getBasicBlocks().getStartBlock();
addr = topblock->getStart();
}
if (hi != (Varnode*)0) {
concatop = data.newOp(2,addr);
// Do we need to pick something other than a unique????
whole = data.newUniqueOut(wholesize,concatop);
data.opSetOpcode(concatop,CPUI_PIECE);
data.opSetOutput(concatop,whole);
data.opSetInput(concatop,hi,0);
data.opSetInput(concatop,lo,1);
}
else {
concatop = data.newOp(1,addr);
whole = data.newUniqueOut(wholesize,concatop);
data.opSetOpcode(concatop,CPUI_INT_ZEXT);
data.opSetOutput(concatop,whole);
data.opSetInput(concatop,lo,0);
}
if (defblock != (BlockBasic *)0)
data.opInsertAfter(concatop,defpoint);
else
data.opInsertBegin(concatop,topblock);
defpoint = concatop;
defblock = concatop->getParent();
}
/// If the \b whole does not already exist, it is created as a \e unique register.
/// The new Varnode must later be set explicitly as the output of some PcodeOp.
/// \param data is the function owning the Varnode pieces
void SplitVarnode::findCreateOutputWhole(Funcdata &data)
{ // Create the actual -whole- varnode
lo->setPrecisLo(); // Mark the pieces
hi->setPrecisHi();
if (whole != (Varnode *)0) return;
whole = data.newUnique(wholesize);
}
/// If the pieces can be treated as a contiguous whole, use the same storage location to construct the \b whole,
/// otherwise use a \b join address for storage.
/// \param data is the function owning the pieces
void SplitVarnode::createJoinedWhole(Funcdata &data)
{
lo->setPrecisLo();
hi->setPrecisHi();
if (whole != (Varnode *)0) return;
Address newaddr;
if (!isAddrTiedContiguous(lo,hi,newaddr)) {
newaddr = data.getArch()->constructJoinAddress(data.getArch()->translate,hi->getAddr(),hi->getSize(),
lo->getAddr(),lo->getSize());
}
whole = data.newVarnode(wholesize,newaddr);
whole->setWriteMask();
}
/// Assume \b lo was initially defined in some other way but now needs to be defined as a split from
/// a new \b whole Varnode. The original PcodeOp defining \b lo is transformed into a CPUI_SUBPIECE.
/// The method findCreateOutputWhole() must already have been called on \b this.
void SplitVarnode::buildLoFromWhole(Funcdata &data)
{
PcodeOp *loop = lo->getDef();
if (loop == (PcodeOp *)0)
throw LowlevelError("Building low piece that was originally undefined");
vector<Varnode *> inlist;
inlist.push_back(whole);
inlist.push_back(data.newConstant(4,0));
if (loop->code() == CPUI_MULTIEQUAL) {
// When converting the MULTIEQUAL to a SUBPIECE, we need to reinsert the op so that we don't
// get a break in the sequence of MULTIEQUALs at the beginning of the block
BlockBasic *bl = loop->getParent();
data.opUninsert(loop);
data.opSetOpcode(loop,CPUI_SUBPIECE);
data.opSetAllInput(loop,inlist);
data.opInsertBegin(loop,bl);
}
else if (loop->code() == CPUI_INDIRECT) {
// When converting an INDIRECT to a SUBPIECE, we need to reinsert the op AFTER the affector
PcodeOp *affector = PcodeOp::getOpFromConst(loop->getIn(1)->getAddr());
if (!affector->isDead())
data.opUninsert(loop);
data.opSetOpcode(loop,CPUI_SUBPIECE);
data.opSetAllInput(loop,inlist);
if (!affector->isDead())
data.opInsertAfter(loop,affector);
}
else {
data.opSetOpcode(loop,CPUI_SUBPIECE);
data.opSetAllInput(loop,inlist);
}
}
/// Assume \b hi was initially defined in some other way but now needs to be defined as a split from
/// a new \b whole Varnode. The original PcodeOp defining \b hi is transformed into a CPUI_SUBPIECE.
/// The method findCreateOutputWhole() must already have been called on \b this.
void SplitVarnode::buildHiFromWhole(Funcdata &data)
{
PcodeOp *hiop = hi->getDef();
if (hiop == (PcodeOp *)0)
throw LowlevelError("Building low piece that was originally undefined");
vector<Varnode *> inlist;
inlist.push_back(whole);
inlist.push_back(data.newConstant(4,lo->getSize()));
if (hiop->code() == CPUI_MULTIEQUAL) {
// When converting the MULTIEQUAL to a SUBPIECE, we need to reinsert the op so that we don't
// get a break in the sequence of MULTIEQUALs at the beginning of the block
BlockBasic *bl = hiop->getParent();
data.opUninsert(hiop);
data.opSetOpcode(hiop,CPUI_SUBPIECE);
data.opSetAllInput(hiop,inlist);
data.opInsertBegin(hiop,bl);
}
else if (hiop->code() == CPUI_INDIRECT) {
// When converting the INDIRECT to a SUBPIECE, we need to reinsert AFTER the affector
PcodeOp *affector = PcodeOp::getOpFromConst(hiop->getIn(1)->getAddr());
if (!affector->isDead())
data.opUninsert(hiop);
data.opSetOpcode(hiop,CPUI_SUBPIECE);
data.opSetAllInput(hiop,inlist);
if (!affector->isDead())
data.opInsertAfter(hiop,affector);
}
else {
data.opSetOpcode(hiop,CPUI_SUBPIECE);
data.opSetAllInput(hiop,inlist);
}
}
// void SplitVarnode::buildHiFromLoHalf(Funcdata &data,SplitVarnode &oldin,PcodeOp *newwholeop)
// { // Only the lo half of the new logical whole is explicitly constructed, the old input high
// // is recycled for the hi half of the output, define the new hi half as a SUBPIECE and scan
// // through the uses of the old hi half to see which should be switch to the new hi half
// PcodeOp *newhiop = data.newOp(2,newwholeop->getAddr());
// data.opSetOpcode(newhiop,CPUI_SUBPIECE);
// data.opSetOutput(newhiop,hi); // hi was not defined previously
// data.opSetInput(newhiop,whole,0);
// data.opSetInput(newhiop,data.newConstant(4,lo->getSize()),1);
// data.opInsertAfter(newhiop,newwholeop);
// Varnode *oldhi = oldin.getHi();
// list<PcodeOp *>::const_iterator iter,enditer;
// iter = oldhi->beginDescend();
// enditer = oldhi->endDescend();
// while(iter != enditer) {
// PcodeOp *testop = *iter;
// ++iter;
// int4 ord = testop->compareOrder(newhiop);
// if (ord == 1) { // newhiop executes earlier than testop
// int4 slot = testop->getSlot(oldhi);
// data.opSetInput(testop,hi,slot);
// }
// }
// }
/// Its assumed that \b this is the output of the double precision operation being performed.
/// The \b whole Varnode may not yet exist. This method returns the first PcodeOp where the \b whole
/// needs to exist. If no such PcodeOp exists, null is returned.
/// \return the first PcodeOp where the \b whole needs to exist or null
PcodeOp *SplitVarnode::findOutExist(void)
{
if (findWholeBuiltFromPieces()) {
return defpoint;
}
return findEarliestSplitPoint();
}
/// If the logical whole is a constant and is too big to be represented internally return \b true.
/// \return \b true if \b this is a constant and too big
bool SplitVarnode::exceedsConstPrecision(void) const
{
return isConstant() && (wholesize > sizeof(uintb));
}
/// \brief Check if the values in the given Varnodes differ by the given size
///
/// Return \b true, if the (possibly dynamic) value represented by the given \b vn1 plus \b size1
/// produces the value in the given \b vn2. For constants, the values can be computed directly, but
/// otherwise \b vn1 and \b vn2 must be defined by INT_ADD operations from a common ancestor.
/// \param vn1 is the first given Varnode
/// \param vn2 is the second given Varnode
/// \param size1 is the given size to add to \b vn1
/// \return \b true if the values in \b vn1 and \b vn2 are related by the given size
bool SplitVarnode::adjacentOffsets(Varnode *vn1,Varnode *vn2,uintb size1)
{
if (vn1->isConstant()) {
if (!vn2->isConstant()) return false;
return ((vn1->getOffset() + size1) == vn2->getOffset());
}
if (!vn2->isWritten()) return false;
PcodeOp *op2 = vn2->getDef();
if (op2->code() != CPUI_INT_ADD) return false;
if (!op2->getIn(1)->isConstant()) return false;
uintb c2 = op2->getIn(1)->getOffset();
if (op2->getIn(0) == vn1)
return (size1 == c2);
if (!vn1->isWritten()) return false;
PcodeOp *op1 = vn1->getDef();
if (op1->code() != CPUI_INT_ADD) return false;
if (!op1->getIn(1)->isConstant()) return false;
uintb c1 = op1->getIn(1)->getOffset();
if (op1->getIn(0) != op2->getIn(0)) return false;
return ((c1 + size1) == c2);
}
/// \brief Verify that the pointers into the given LOAD/STORE PcodeOps address contiguous memory
///
/// The two given PcodeOps must either both be LOADs or both be STOREs. The pointer for the
/// first PcodeOp is labeled as the most significant piece of the contiguous whole, the
/// second PcodeOp is labeled as the least significant piece. The p-code defining the pointers is examined
/// to determine if the two memory regions being pointed at really form one contiguous region.
/// If the regions are contiguous and the pointer labeling is valid, \b true is returned, the PcodeOps are sorted
/// into \b first and \b second based on Address, and the address space of the memory region is passed back.
/// \param most is the given LOAD/STORE PcodeOp referring to the most significant region
/// \param least is the given LOAD/STORE PcodeOp referring to the least significant region
/// \param first is used to pass back the earliest of the address sorted PcodeOps
/// \param second is used to pass back the latest of the address sorted PcodeOps
/// \param spc is used to pass back the LOAD address space
/// \param sizeres is used to pass back the combined LOAD size
/// \return true if the given PcodeOps are contiguous LOADs
bool SplitVarnode::testContiguousPointers(PcodeOp *most,PcodeOp *least,PcodeOp *&first,PcodeOp *&second,AddrSpace *&spc)
{
spc = least->getIn(0)->getSpaceFromConst();
if (most->getIn(0)->getSpaceFromConst() != spc) return false;
if (spc->isBigEndian()) { // Convert significance order to address order
first = most;
second = least;
}
else {
first = least;
second = most;
}
Varnode *firstptr = first->getIn(1);
if (firstptr->isFree()) return false;
int4 sizeres;
if (first->code() == CPUI_LOAD)
sizeres = first->getOut()->getSize(); // # of bytes read by lowest address load
else // CPUI_STORE
sizeres = first->getIn(2)->getSize();
// Check if the loads are adjacent to each other
return adjacentOffsets(first->getIn(1),second->getIn(1),(uintb)sizeres);
}
/// \brief Return \b true if the given pieces can be melded into a contiguous storage location
///
/// The given Varnodes must be \e address \e tied, and their storage must line up, respecting their
/// significance as pieces.
/// \param lo is the given least significant piece
/// \param hi is the given most significant piece
/// \param res is used to pass back the starting address of the contigous range
/// \return \b true if the pieces are address tied and form a contiguous range
bool SplitVarnode::isAddrTiedContiguous(Varnode *lo,Varnode *hi,Address &res)
{
if (!lo->isAddrTied()) return false;
if (!hi->isAddrTied()) return false;
// Make sure there is no explicit symbol that would prevent the pieces from being joined
SymbolEntry *entryLo = lo->getSymbolEntry();
SymbolEntry *entryHi = hi->getSymbolEntry();
if (entryLo != (SymbolEntry *)0 || entryHi != (SymbolEntry *)0) {
if (entryLo == (SymbolEntry *)0 || entryHi == (SymbolEntry *)0)
return false; // One is marked with a symbol, the other is not
if (entryLo->getSymbol() != entryHi->getSymbol())
return false; // They are part of different symbols
}
AddrSpace *spc = lo->getSpace();
if (spc != hi->getSpace()) return false;
uintb looffset = lo->getOffset();
uintb hioffset = hi->getOffset();
if (spc->isBigEndian()) {
if (hioffset >= looffset) return false;
if (hioffset + hi->getSize() != looffset) return false;
res = hi->getAddr();
}
else {
if (looffset >= hioffset) return false;
if (looffset + lo->getSize() != hioffset) return false;
res = lo->getAddr();
}
return true;
}
/// \brief Create a list of all the possible pairs that contain the same logical value as the given Varnode
///
/// The given Varnode is assumed to be the logical whole that is being used in a double precision calculation.
/// At least one of the most or least significant pieces must be extracted from the whole and must be
/// marked as a double precision piece.
/// \param w is the given Varnode whole
/// \param splitvec is the container for holding any discovered SplitVarnodes
void SplitVarnode::wholeList(Varnode *w,vector<SplitVarnode> &splitvec)
{
SplitVarnode basic;
basic.whole = w;
basic.hi = (Varnode *)0;
basic.lo = (Varnode *)0;
basic.wholesize = w->getSize();
list<PcodeOp *>::const_iterator iter,enditer;
iter = basic.whole->beginDescend();
enditer = basic.whole->endDescend();
int4 res = 0;
while(iter != enditer) {
PcodeOp *subop = *iter;
++iter;
if (subop->code() != CPUI_SUBPIECE) continue;
Varnode *vn = subop->getOut();
if (vn->isPrecisHi()) {
if (subop->getIn(1)->getOffset() != basic.wholesize - vn->getSize()) continue;
basic.hi = vn;
res |= 2;
}
else if (vn->isPrecisLo()) {
if (subop->getIn(1)->getOffset() != 0) continue;
basic.lo = vn;
res |= 1;
}
}
if (res==0) return;
if (res == 3 && (basic.lo->getSize() + basic.hi->getSize() != basic.wholesize))
return;
splitvec.push_back(basic);
findCopies(basic,splitvec);
}
/// \brief Find copies from (the pieces of) the given SplitVarnode
///
/// Scan for each piece being used as input to COPY operations. If the each piece is
/// copied within the same basic block to contiguous storage locations, create a new
/// SplitVarnode from COPY outputs and add it to the list.
/// \param in is the given SplitVarnode
/// \param splitvec is the container for holding SplitVarnode copies
void SplitVarnode::findCopies(const SplitVarnode &in,vector<SplitVarnode> &splitvec)
{
if (!in.hasBothPieces()) return;
list<PcodeOp *>::const_iterator iter,enditer;
iter = in.getLo()->beginDescend();
enditer = in.getLo()->endDescend();
while(iter != enditer) {
PcodeOp *loop = *iter;
++iter;
if (loop->code() != CPUI_COPY) continue;
Varnode *locpy = loop->getOut();
Address addr = locpy->getAddr(); // Calculate address of hi part
if (addr.isBigEndian())
addr = addr - (in.getHi()->getSize());
else
addr = addr + locpy->getSize();
list<PcodeOp *>::const_iterator iter2,enditer2;
iter2 = in.getHi()->beginDescend();
enditer2 = in.getHi()->endDescend();
while(iter2 != enditer2) {
PcodeOp *hiop = *iter2;
++iter2;
if (hiop->code() != CPUI_COPY) continue;
Varnode *hicpy = hiop->getOut();
if (hicpy->getAddr() != addr) continue;
if (hiop->getParent() != loop->getParent()) continue;
SplitVarnode newsplit;
newsplit.initAll(in.getWhole(),locpy,hicpy);
splitvec.push_back(newsplit);
}
}
}
/// \brief For the given CBRANCH PcodeOp, pass back the \b true and \b false basic blocks
///
/// The result depends on the \e boolean \e flip property of the CBRANCH, and the user can
/// also flip the meaning of the branches.
/// \param boolop is the given CBRANCH PcodeOp
/// \param flip is \b true if the caller wants to flip the meaning of the blocks
/// \param trueout is used to pass back the true fall-through block
/// \param falseout is used to pass back the false fall-through block
void SplitVarnode::getTrueFalse(PcodeOp *boolop,bool flip,BlockBasic *&trueout,BlockBasic *&falseout)
{
BlockBasic *parent = boolop->getParent();
BlockBasic *trueblock = (BlockBasic *)parent->getTrueOut();
BlockBasic *falseblock =(BlockBasic *)parent->getFalseOut();
if (boolop->isBooleanFlip() != flip) {
trueout = falseblock;
falseout = trueblock;
}
else {
trueout = trueblock;
falseout = falseblock;
}
}
/// \brief Return \b true if the basic block containing the given CBRANCH PcodeOp performs no other operation.
///
/// The basic block can contain the CBRANCH and the one PcodeOp producing the boolean value.
/// Otherwise \b false is returned.
/// \param branchop is the given CBRANCH
/// \return \b true if the parent basic block performs only the branch operation
bool SplitVarnode::otherwiseEmpty(PcodeOp *branchop)
{
BlockBasic *bl = branchop->getParent();
if (bl->sizeIn() != 1) return false;
PcodeOp *otherop = (PcodeOp *)0;
Varnode *vn = branchop->getIn(1);
if (vn->isWritten())
otherop = vn->getDef();
list<PcodeOp *>::const_iterator iter,enditer;
iter = bl->beginOp();
enditer = bl->endOp();
while(iter != enditer) {
PcodeOp *op = *iter;
++iter;
if (op == otherop) continue;
if (op == branchop) continue;
return false;
}
return true;
}
/// \brief Verify that the given PcodeOp is a CPUI_INT_MULT by -1
///
/// The PcodeOp must be a CPUI_INT_MULT and the second operand must be a constant -1.
/// \param op is the given PcodeOp
/// \return \b true if the PcodeOp is a multiple by -1
bool SplitVarnode::verifyMultNegOne(PcodeOp *op)
{
if (op->code() != CPUI_INT_MULT) return false;
Varnode *in1 = op->getIn(1);
if (!in1->isConstant()) return false;
if (in1->getOffset() != calc_mask(in1->getSize())) return false;
return true;
}
/// \brief Check that the logical version of a (generic) binary double-precision operation can be created
///
/// This checks only the most generic aspects of the calculation. The input and output whole Varnodes
/// must already exist or be creatable. The point where the output Varnode must exist is identified
/// and returned. If the binary operation cannot be created, null is returned.
/// \param out is the output of the binary operation
/// \param in1 is the first input of the binary operation
/// \param in2 is the second input of the binary operation
/// \return the first PcodeOp where the output whole must exist
PcodeOp *SplitVarnode::prepareBinaryOp(SplitVarnode &out,SplitVarnode &in1,SplitVarnode &in2)
{
PcodeOp *existop = out.findOutExist(); // Find point where output whole needs to exist
if (existop == (PcodeOp *)0) return existop; // If we can find no such point return false;
if (!in1.isWholeFeasible(existop)) return (PcodeOp *)0;
if (!in2.isWholeFeasible(existop)) return (PcodeOp *)0;
return existop;
}
/// \brief Rewrite a double precision binary operation by replacing the pieces with unified Varnodes
///
/// This assumes that we have checked that the transformation is possible via the various
/// verify and prepare methods. After this method is called, the logical inputs and output of
/// the calculation will exist as real Varnodes.
/// \param data is the function owning the operation
/// \param out is the output of the binary operation