forked from cseagle/blc
-
Notifications
You must be signed in to change notification settings - Fork 0
/
fspec.hh
1556 lines (1424 loc) · 93.9 KB
/
fspec.hh
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.
*/
/// \file fspec.hh
/// \brief Definitions for specifying functions prototypes
#ifndef __CPUI_FSPEC__
#define __CPUI_FSPEC__
#include "op.hh"
#include "rangemap.hh"
class JoinRecord;
/// \brief Exception thrown when a prototype can't be modeled properly
struct ParamUnassignedError : public LowlevelError {
ParamUnassignedError(const string &s) : LowlevelError(s) {} ///< Constructor
};
/// \brief A contiguous range of memory that can be used to pass parameters
///
/// This range can be used to pass a single parameter (isExclusion() == \b true). This
/// is intended to model a parameter passed in a register. The logical value does not
/// have to fill the entire range. The size in bytes can range from a minimum, getMinSize(),
/// to the whole range, getSize(). Justification and extension of the logical value within
/// the range can be specified.
///
/// Alternately the range can be used as a resource for multiple parameters
/// (isExclusion() == \b false). In this case, the parameters are allocated sequentially
/// (usually) starting from the front of the range. The amount of space consumed by each
/// parameter is dictated by an \e alignment setting in bytes.
///
/// A ParamEntry can be associated with a particular class of data-types. Usually:
/// - TYPE_UNKNOWN for general purpose parameters
/// - TYPE_FLOAT for dedicated floating-point registers
class ParamEntry {
public:
enum {
force_left_justify = 1, ///< Big endian values are left justified within their slot
reverse_stack = 2, ///< Slots (for \e non-exlusion entries) are allocated in reverse order
smallsize_zext = 4, ///< Assume values that are below the max \b size are zero extended into this container
smallsize_sext = 8, ///< Assume values that are below the max \b size are sign extended into this container
// is_big_endian = 16, ///< Set if this value should be treated as big endian
smallsize_inttype = 32, ///< Assume values that are below the max \b size are sign OR zero extended based on integer type
smallsize_floatext = 64, ///< Assume values smaller than max \b size are floating-point extended to full size
extracheck_high = 128, ///< Perform extra checks during parameter recovery on most sig portion of the double
extracheck_low = 256 ///< Perform extra checks during parameter recovery on least sig portion of the double
};
private:
uint4 flags; ///< Boolean properties of the parameter
type_metatype type; ///< Data-type class that this entry must match
int4 group; ///< Group of (mutually exclusive) entries that this entry belongs to
int4 groupsize; ///< The number of consecutive groups taken by the entry
AddrSpace *spaceid; ///< Address space containing the range
uintb addressbase; ///< Starting offset of the range
int4 size; ///< Size of the range in bytes
int4 minsize; ///< Minimum bytes allowed for the logical value
int4 alignment; ///< How much alignment (0 means only 1 logical value is allowed)
int4 numslots; ///< (Maximum) number of slots that can store separate parameters
JoinRecord *joinrec; ///< Non-null if this is logical variable from joined pieces
void resolveJoin(void); ///< If the ParamEntry is initialized with a \e join address, cache the join record
/// \brief Is the logical value left-justified within its container
bool isLeftJustified(void) const { return (((flags&force_left_justify)!=0)||(!spaceid->isBigEndian())); }
public:
ParamEntry(int4 grp) { group=grp; } ///< Constructor for use with restoreXml
ParamEntry(type_metatype t,int4 grp,int4 grpsize,const Address &loc,int4 sz,int4 mnsz,int4 align,bool normalstack);
int4 getGroup(void) const { return group; } ///< Get the group id \b this belongs to
int4 getGroupSize(void) const { return groupsize; } ///< Get the number of groups occupied by \b this
int4 getSize(void) const { return size; } ///< Get the size of the memory range in bytes.
int4 getMinSize(void) const { return minsize; } ///< Get the minimum size of a logical value contained in \b this
int4 getAlign(void) const { return alignment; } ///< Get the alignment of \b this entry
type_metatype getType(void) const { return type; } ///< Get the data-type class associated with \b this
bool isExclusion(void) const { return (alignment==0); } ///< Return \b true if this holds a single parameter exclusively
bool isReverseStack(void) const { return ((flags & reverse_stack)!=0); } ///< Return \b true if parameters are allocated in reverse order
bool contains(const ParamEntry &op2) const; ///< Does \b this contain the indicated entry.
bool containedBy(const Address &addr,int4 sz) const; ///< Is this entry contained by the given range
int4 justifiedContain(const Address &addr,int4 sz) const; ///< Calculate endian aware containment
bool getContainer(const Address &addr,int4 sz,VarnodeData &res) const;
OpCode assumedExtension(const Address &addr,int4 sz,VarnodeData &res) const;
int4 getSlot(const Address &addr,int4 skip) const;
AddrSpace *getSpace(void) const { return spaceid; } ///< Get the address space containing \b this entry
uintb getBase(void) const { return addressbase; } ///< Get the starting offset of \b this entry
Address getAddrBySlot(int4 &slot,int4 sz) const;
void restoreXml(const Element *el,const AddrSpaceManager *manage,bool normalstack);
void extraChecks(list<ParamEntry> &entry);
bool isParamCheckHigh(void) const { return ((flags & extracheck_high)!=0); } ///< Return \b true if there is a high overlap
bool isParamCheckLow(void) const { return ((flags & extracheck_low)!=0); } ///< Return \b true if there is a low overlap
};
/// \brief Class for storing ParamEntry objects in an interval range (rangemap)
class ParamEntryRange {
uintb first; ///< Starting offset of the ParamEntry's range
uintb last; ///< Ending offset of the ParamEntry's range
int4 position; ///< Position of the ParamEntry within the entire prototype list
ParamEntry *entry; ///< Pointer to the actual ParamEntry
/// \brief Helper class for initializing ParamEntryRange in a range map
class InitData {
friend class ParamEntryRange;
int4 position; ///< Position (within the full list) being assigned to the ParamEntryRange
ParamEntry *entry; ///< Underlying ParamEntry being assigned to the ParamEntryRange
public:
InitData(int4 pos,ParamEntry *e) { position = pos; entry = e; } ///< Constructor
};
/// \brief Helper class for subsorting on position
class SubsortPosition {
int4 position; ///< The position value
public:
SubsortPosition(void) {} ///< Constructor for use with rangemap
SubsortPosition(int4 pos) { position = pos; } ///< Construct given position
SubsortPosition(bool val) { position = val ? 1000000 : 0; } ///< Constructor minimal/maximal subsort
bool operator<(const SubsortPosition &op2) { return position < op2.position; } ///< Compare operation
};
public:
typedef uintb linetype; ///< The linear element for a rangemap
typedef SubsortPosition subsorttype; ///< The sub-sort object for a rangemap
typedef InitData inittype; ///< Initialization data for a ScopeMapper
ParamEntryRange(void) {} ///< Constructor for use with rangemap
void initialize(const inittype &data,uintb f,uintb l) {
first = f; last = l; position = data.position; entry = data.entry; } ///< Initialize the range
uintb getFirst(void) const { return first; } ///< Get the first address in the range
uintb getLast(void) const { return last; } ///< Get the last address in the range
subsorttype getSubsort(void) const { return SubsortPosition(position); } ///< Get the sub-subsort object
ParamEntry *getParamEntry(void) const { return entry; } ///< Get pointer to actual ParamEntry
};
typedef rangemap<ParamEntryRange> ParamEntryResolver; ///< A map from offset to ParamEntry
/// \brief A register or memory register that may be used to pass a parameter or return value
///
/// The parameter recovery utilities (see ParamActive) use this to denote a putative
/// parameter passing storage location. It is made up of the address and size of the memory range,
/// a set of properties about the use of the range (as a parameter) in context, and a link to
/// the matching part of the PrototypeModel.
///
/// Data-flow for the putative parameter is held directly by a Varnode. To quickly map to the
/// Varnode (which may or may not exist at points during the ParamTrial lifetime), the concept
/// of \b slot is used. ParamTrials are assigned a \e slot, starting at 1. For sub-function parameters,
/// this represents the actual input index of the Varnode in the corresponding CALL or CALLIND op.
/// For parameters, this gives the position within the list of possible input Varnodes in address order.
/// The \e slot ordering varies over the course of analysis and is unlikely to match
/// the final parameter ordering. The ParamTrial comparator sorts the trials in final parameter ordering.
class ParamTrial {
public:
enum {
checked = 1, ///< Trial has been checked
used = 2, ///< Trial is definitely used (final verdict)
defnouse = 4, ///< Trial is definitely not used
active = 8, ///< Trial looks active (hint that it is used)
unref = 16, ///< There is no direct reference to this parameter trial
killedbycall = 32, ///< Data in this location is unlikely to flow thru a func and still be a param
rem_formed = 64, ///< The trial is built out of a remainder operation
indcreate_formed = 128, ///< The trial is built out of an indirect creation
condexe_effect = 256 ///< This trial may be affected by conditional execution
};
private:
uint4 flags; ///< Boolean properties of the trial
Address addr; ///< Starting address of the memory range
int4 size; ///< Number of bytes in the memory range
int4 slot; ///< Slot assigned to this trial
const ParamEntry *entry; ///< PrototypeModel entry matching this trial
int4 offset; ///< "justified" offset into entry
public:
/// \brief Construct from components
ParamTrial(const Address &ad,int4 sz,int4 sl) { addr = ad; size = sz; slot = sl; flags=0; entry=(ParamEntry *)0; offset=-1; }
const Address &getAddress(void) const { return addr; } ///< Get the starting address of \b this trial
int4 getSize(void) const { return size; } ///< Get the number of bytes in \b this trial
int4 getSlot(void) const { return slot; } ///< Get the \e slot associated with \b this trial
void setSlot(int4 val) { slot = val; } ///< Set the \e slot associated with \b this trial
const ParamEntry *getEntry(void) const { return entry; } ///< Get the model entry associated with \b this trial
int4 getOffset(void) const { return offset; } ///< Get the offset associated with \b this trial
void setEntry(const ParamEntry *ent,int4 off) { entry=ent; offset=off; } ///< Set the model entry for this trial
void markUsed(void) { flags |= used; } ///< Mark the trial as a formal parameter
void markActive(void) { flags |= (active|checked); } ///< Mark that trial is actively used (in data-flow)
void markInactive(void) { flags &= ~((uint4)active); flags |= checked; } ///< Mark that trial is not actively used
void markNoUse(void) { flags &= ~((uint4)(active|used)); flags |= (checked|defnouse); } ///< Mark trial as definitely \e not a parameter
void markUnref(void) { flags |= (unref|checked); slot = -1; } ///< Mark that \b this trial has no Varnode representative
void markKilledByCall(void) { flags |= killedbycall; } ///< Mark that \b this storage is \e killed-by-call
bool isChecked(void) const { return ((flags & checked)!=0); } ///< Has \b this trial been checked
bool isActive(void) const { return ((flags & active)!=0); } ///< Is \b this trial actively used in data-flow
bool isDefinitelyNotUsed(void) const { return ((flags & defnouse)!=0); } ///< Is \b this trial as definitely not a parameter
bool isUsed(void) const { return ((flags & used)!=0); } ///< Is \b this trial as a formal parameter
bool isUnref(void) const { return ((flags & unref)!=0); } ///< Does \b this trial not have a Varnode representative
bool isKilledByCall(void) const { return ((flags & killedbycall)!=0); } ///< Is \b this storage \e killed-by-call
void setRemFormed(void) { flags |= rem_formed; } ///< Mark that \b this is formed by a INT_REM operation
bool isRemFormed(void) const { return ((flags & rem_formed)!=0); } ///< Is \b this formed by a INT_REM operation
void setIndCreateFormed(void) { flags |= indcreate_formed; } ///< Mark \b this trial as formed by \e indirect \e creation
bool isIndCreateFormed(void) const { return ((flags & indcreate_formed)!=0); } ///< Is \b this trial formed by \e indirect \e creation
void setCondExeEffect(void) { flags |= condexe_effect; } ///< Mark \b this trial as possibly affected by conditional execution
bool hasCondExeEffect(void) const { return ((flags & condexe_effect)!=0); } ///< Is \b this trial possibly affected by conditional execution
int4 slotGroup(void) const { return entry->getSlot(addr,size-1); } ///< Get position of \b this within its parameter \e group
void setAddress(const Address &ad,int4 sz) { addr=ad; size=sz; } ///< Reset the memory range of \b this trial
ParamTrial splitHi(int4 sz) const; ///< Create a trial representing the first part of \b this
ParamTrial splitLo(int4 sz) const; ///< Create a trial representing the last part of \b this
bool testShrink(const Address &newaddr,int4 sz) const; ///< Test if \b this trial can be made smaller
bool operator<(const ParamTrial &b) const; ///< Sort trials in formal parameter order
};
/// \brief Container class for ParamTrial objects
///
/// The parameter analysis algorithms use this class to maintain the collection
/// of parameter trials being actively considered for a given function. It holds the
/// ParamTrial objects and other information about the current state of analysis.
///
/// Trials are maintained in two stages, \e before parameter decisions have been made and \e after.
/// Before, trials are in input index order relative to the CALL or CALLIND op for a sub-function, or
/// they are in address order for input Varnodes to the active function.
/// After, the trials are put into formal parameter order, as dictated by the PrototypeModel.
class ParamActive {
vector<ParamTrial> trial; ///< The list of parameter trials
int4 slotbase; ///< Slot where next parameter will go
int4 stackplaceholder; ///< Which call input slot holds the stack placeholder
int4 numpasses; ///< Number of attempts at evaluating parameters
int4 maxpass; ///< Number of passes before we assume we have seen all params
bool isfullychecked; ///< True if all trials are fully examined (and no new trials are expected)
bool needsfinalcheck; ///< Should a final pass be made on trials (to take into account control-flow changes)
bool recoversubcall; ///< True if \b this is being used to recover prototypes of a sub-function call
public:
ParamActive(bool recoversub); ///< Constructor an empty container
void clear(void); ///< Reset to an empty container
void registerTrial(const Address &addr,int4 sz); ///< Add a new trial to the container
int4 getNumTrials(void) const { return trial.size(); } ///< Get the number of trials in \b this container
ParamTrial &getTrial(int4 i) { return trial[i]; } ///< Get the i-th trial
const ParamTrial &getTrialForInputVarnode(int4 slot) const; ///< Get trial corresponding to the given input Varnode
int4 whichTrial(const Address &addr,int4 sz) const; ///< Get the trial overlapping with the given memory range
bool needsFinalCheck(void) const { return needsfinalcheck; } ///< Is a final check required
void markNeedsFinalCheck(void) { needsfinalcheck = true; } ///< Mark that a final check is required
bool isRecoverSubcall(void) const { return recoversubcall; } ///< Are these trials for a call to a sub-function
bool isFullyChecked(void) const { return isfullychecked; } ///< Are all trials checked with no new trials expected
void markFullyChecked(void) { isfullychecked = true; } ///< Mark that all trials are checked
void setPlaceholderSlot(void) { stackplaceholder = slotbase; slotbase += 1; } ///< Establish a stack placedholder slot
void freePlaceholderSlot(void); ///< Free the stack placeholder slot
int4 getNumPasses(void) const { return numpasses; } ///< How many trial analysis passes were performed
int4 getMaxPass(void) const { return maxpass; } ///< What is the maximum number of passes
void setMaxPass(int4 val) { maxpass = val; } ///< Set the maximum number of passes
void finishPass(void) { numpasses += 1; } ///< Mark that an analysis pass has completed
void sortTrials(void) { sort(trial.begin(),trial.end()); } ///< Sort the trials in formal parameter order
void deleteUnusedTrials(void); ///< Remove trials that were found not to be parameters
void splitTrial(int4 i,int4 sz); ///< Split the given trial in two
void joinTrial(int4 slot,const Address &addr,int4 sz); ///< Join adjacent parameter trials
int4 getNumUsed(void) const; ///< Get number of trials marked as formal parameters
/// \brief Test if the given trial can be shrunk to the given range
///
/// \param i is the index of the given trial
/// \param addr is the new address
/// \param sz is the new size
/// \return true if the trial can be shrunk to the new range
bool testShrink(int4 i,const Address &addr,int4 sz) const { return trial[i].testShrink(addr,sz); }
/// \brief Shrink the given trial to a new given range
///
/// \param i is the index of the given trial
/// \param addr is the new range's starting address
/// \param sz is the new range's size in bytes
void shrink(int4 i,const Address &addr,int4 sz) { trial[i].setAddress(addr,sz); }
};
/// \brief A special space for encoding FuncCallSpecs
///
/// It is efficient and convenient to store the main subfunction
/// object (FuncCallSpecs) in the pcode operation which is actually making the
/// call. This address space allows a FuncCallSpecs to be encoded
/// as an address which replaces the formally encoded address of
/// the function being called, when manipulating the operation
/// internally. The space stored in the encoded address is
/// this special \b fspec space, and the offset is the actual
/// value of the pointer
class FspecSpace : public AddrSpace {
public:
FspecSpace(AddrSpaceManager *m,const Translate *t,const string &nm,int4 ind); ///< Constructor
virtual void saveXmlAttributes(ostream &s,uintb offset) const;
virtual void saveXmlAttributes(ostream &s,uintb offset,int4 size) const;
virtual void printRaw(ostream &s,uintb offset) const;
virtual void saveXml(ostream &s) const;
virtual void restoreXml(const Element *el);
};
/// \brief Basic elements of a parameter: address, data-type, properties
struct ParameterPieces {
Address addr; ///< Storage address of the parameter
Datatype *type; ///< The datatype of the parameter
uint4 flags; ///< additional attributes of the parameter
};
/// \brief Description of the indirect effect a sub-function has on a memory range
///
/// This object applies only to the specific memory range, which is seen from the
/// point of view of the calling function as a particular
/// sub-function gets called. The main enumeration below lists the possible effects.
class EffectRecord {
public:
enum {
unaffected = 1, ///< The sub-function does not change the value at all
killedbycall = 2, ///< The memory is changed and is completely unrelated to its original value
return_address = 3, ///< The memory is being used to pass back a return value from the sub-function
unknown_effect = 4 ///< An unknown effect (indicates the absence of an EffectRecord)
};
private:
VarnodeData address; ///< The memory range affected
uint4 type; ///< The type of effect
public:
EffectRecord(void) {} ///< Constructor for use with restoreXml()
EffectRecord(const EffectRecord &op2) { address = op2.address; type = op2.type; } ///< Copy constructor
EffectRecord(const Address &addr,int4 size); ///< Construct a memory range with an unknown effect
EffectRecord(const ParamEntry &entry,uint4 t); ///< Construct an effect on a parameter storage location
EffectRecord(const VarnodeData &addr,uint4 t); ///< Construct an effect on a memory range
uint4 getType(void) const { return type; } ///< Get the type of effect
Address getAddress(void) const { return Address(address.space,address.offset); } ///< Get the starting address of the affected range
int4 getSize(void) const { return address.size; } ///< Get the size of the affected range
bool operator<(const EffectRecord &op2) const; ///< Comparator for EffectRecords
bool operator==(const EffectRecord &op2) const; ///< Equality operator
bool operator!=(const EffectRecord &op2) const; ///< Inequality operator
void saveXml(ostream &s) const; ///< Save the record to an XML stream
void restoreXml(uint4 grouptype,const Element *el,const AddrSpaceManager *manage); ///< Restore the record from an XML stream
};
/// A group of ParamEntry objects that form a complete set for passing
/// parameters in one direction (either input or output). The main tasks this class must
/// perform are:
/// - possibleParam() Quick test if a Varnode could ever be a parameter with this prototype
/// - fillinMap() Select trials completing prototype, given analysis info
/// - assignMap() Derive slot->address map, given a list of types
/// - checkJoin() Can two parameters be considered/converted into a single logical parameter
class ParamList {
public:
enum {
p_standard, ///< Standard input parameter model
p_standard_out, ///< Standard output (return value) model
p_register, ///< Unordered parameter passing locations model
p_merged ///< A merged model (multiple models merged together)
};
virtual ~ParamList(void) {} ///< Destructor
virtual uint4 getType(void) const=0; ///< Get the type of parameter list
/// \brief Given list of data-types, map the list positions to storage locations
///
/// If we know the function prototype, recover how parameters are actually stored using the model.
/// \param proto is the ordered list of data-types
/// \param isinput is \b true for the input prototype, \b false for output prototype
/// \param typefactory is the TypeFactory (for constructing pointers)
/// \param res will contain the storage locations corresponding to the datatypes
virtual void assignMap(const vector<Datatype *> &proto,bool isinput,
TypeFactory &typefactory,vector<ParameterPieces> &res) const=0;
/// \brief Given an unordered list of storage locations, calculate a function prototype
///
/// A list of input (or output) trials is given, which may have holes, invalid inputs etc. Decide
/// on the formal ordered parameter list. Trials within the ParamActive are added, removed, or
/// reordered as needed.
/// \param active is the given list of trials
virtual void fillinMap(ParamActive *active) const=0;
/// \brief Check if the given two storage locations can represent a single logical parameter
///
/// Within the conventions of this model, do the two (hi/lo) locations represent
/// consecutive parameter locations that can be replaced by a single logical parameter.
/// \param hiaddr is the address of the most significant part of the value
/// \param hisize is the size of the most significant part in bytes
/// \param loaddr is the address of the least significant part of the value
/// \param losize is the size of the least significant part in bytes
/// \return \b true if the two pieces can be joined
virtual bool checkJoin(const Address &hiaddr,int4 hisize,const Address &loaddr,int4 losize) const=0;
/// \brief Check if it makes sense to split a single storage location into two parameters
///
/// A storage location and split point is provided, implying two new storage locations. Does
/// \b this model allow these locations to be considered parameters.
/// \param loc is the starting address of provided storage location
/// \param size is the size of the location in bytes
/// \param splitpoint is the number of bytes to consider in the first (in address order) piece
/// \return \b true if the storage location can be split
virtual bool checkSplit(const Address &loc,int4 size,int4 splitpoint) const=0;
/// \brief Characterize whether the given range overlaps parameter storage
///
/// Does the range naturally fit inside a potential parameter entry from this list or does
/// it contain a parameter entry. Return one of three values indicating this characterization:
/// - 0 means there is no intersection between the range and any parameter in this list
/// - 1 means that at least one parameter contains the range in a properly justified manner
/// - 2 means no parameter contains the range, but the range contains at least one ParamEntry
/// \param loc is the starting address of the given range
/// \param size is the number of bytes in the given range
/// \return the characterization code
virtual int4 characterizeAsParam(const Address &loc,int4 size) const=0;
/// \brief Does the given storage location make sense as a parameter
///
/// Within \b this model, decide if the storage location can be considered a parameter.
/// \param loc is the starting address of the storage location
/// \param size is the number of bytes in the storage location
/// \return \b true if the location can be a parameter
virtual bool possibleParam(const Address &loc,int4 size) const=0;
/// \brief Pass-back the slot and slot size for the given storage location as a parameter
///
/// This checks if the given storage location acts as a parameter in \b this model and
/// passes back the number of slots that it occupies.
/// \param loc is the starting address of the storage location
/// \param size is the number of bytes in the storage location
/// \param slot if the \e slot number to pass back
/// \param slotsize is the number of consumed slots to pass back
/// \return \b true if the location can be a parameter
virtual bool possibleParamWithSlot(const Address &loc,int4 size,int4 &slot,int4 &slotsize) const=0;
/// \brief Pass-back the biggest parameter contained within the given range
///
/// \param loc is the starting address of the given range
/// \param size is the number of bytes in the range
/// \param res will hold the parameter storage description being passed back
/// \return \b true if there is at least one parameter contained in the range
virtual bool getBiggestContainedParam(const Address &loc,int4 size,VarnodeData &res) const=0;
/// \brief Check if the given storage location looks like an \e unjustified parameter
///
/// The storage for a value may be contained in a normal parameter location but be
/// unjustified within that container, i.e. the least significant bytes are not being used.
/// If this is the case, pass back the full parameter location and return \b true.
/// \param loc is the starting address of the given storage
/// \param size is the number of bytes in the given storage
/// \param res is the full parameter storage to pass back
/// \return \b true if the given storage is unjustified within its parameter container
virtual bool unjustifiedContainer(const Address &loc,int4 size,VarnodeData &res) const=0;
/// \brief Get the type of extension and containing parameter for the given storage
///
/// If the given storage is properly contained within a normal parameter and the model
/// typically extends a small value into the full container, pass back the full container
/// and the type of extension.
/// \param addr is the starting address of the given storage
/// \param size is the number of bytes in the given storage
/// \param res is the parameter storage to pass back
/// \return the extension operator (INT_ZEXT INT_SEXT) or INT_COPY if there is no extension.
/// INT_PIECE indicates the extension is determined by the specific prototype.
virtual OpCode assumedExtension(const Address &addr,int4 size,VarnodeData &res) const=0;
/// \brief Get the address space associated with any stack based parameters in \b this list.
///
/// \return the stack address space, if \b this models parameters passed on the stack, NULL otherwise
virtual AddrSpace *getSpacebase(void) const=0;
/// \brief For a given address space, collect all the parameter locations within that space
///
/// Pass back the memory ranges for any parameter that is stored in the given address space.
/// \param spc is the given address space
/// \param res will hold the set of matching memory ranges
virtual void getRangeList(AddrSpace *spc,RangeList &res) const=0;
/// \brief Return the maximum heritage delay across all possible parameters
///
/// Depending on the address space, data-flow for a parameter may not be available until
/// extra transform passes have completed. This method returns the number of passes
/// that must occur before we can guarantee that all parameters have data-flow info.
/// \return the maximum number of passes across all parameters in \b this model
virtual int4 getMaxDelay(void) const=0;
/// \brief Restore the model from an XML stream
///
/// \param el is the root \<input> or \<output> element
/// \param manage is used to resolve references to address spaces
/// \param effectlist is a container collecting EffectRecords across all parameters
/// \param normalstack is \b true if parameters are pushed on the stack in the normal order
virtual void restoreXml(const Element *el,const AddrSpaceManager *manage,vector<EffectRecord> &effectlist,bool normalstack)=0;
virtual ParamList *clone(void) const=0; ///< Clone this parameter list model
};
/// \brief A standard model for parameters as an ordered list of storage resources
///
/// This is a configurable model for passing (input) parameters as a list to a function.
/// The model allows 1 or more resource lists based on data-type, either TYPE_UNKNOWN for
/// general purpose or TYPE_FLOAT for floating-point registers. Within a resource list,
/// any number of parameters can be used but they must come starting at the beginning of
/// the list with no \e holes (skipped resources). A resource list can include (at the end)
/// \e stack parameters that are allocated based on an alignment. Optionally, the model supports
/// converting data-types larger than a specified size to pointers within the parameter list.
class ParamListStandard : public ParamList {
protected:
int4 numgroup; ///< Number of \e groups in this parameter convention
int4 maxdelay; ///< Maximum heritage delay across all parameters
int4 pointermax; ///< If non-zero, maximum size of a data-type before converting to a pointer
bool thisbeforeret; ///< Does a \b this parameter come before a hidden return parameter
int4 nonfloatgroup; ///< Group of first entry which is not marked float
list<ParamEntry> entry; ///< The ordered list of parameter entries
vector<ParamEntryResolver *> resolverMap; ///< Map from space id to resolver
AddrSpace *spacebase; ///< Address space containing relative offset parameters
const ParamEntry *findEntry(const Address &loc,int4 size) const; ///< Given storage location find matching ParamEntry
Address assignAddress(const Datatype *tp,vector<int4> &status) const; ///< Assign storage for given parameter data-type
void buildTrialMap(ParamActive *active) const; ///< Build map from parameter trials to model ParamEntrys
void separateFloat(ParamActive *active,int4 &floatstart,int4 &floatstop,int4 &start,int4 &stop) const;
void forceExclusionGroup(ParamActive *active) const;
void forceNoUse(ParamActive *active,int4 start,int4 stop) const;
void forceInactiveChain(ParamActive *active,int4 maxchain,int4 start,int4 stop) const;
void calcDelay(void); ///< Calculate the maximum heritage delay for any potential parameter in this list
void populateResolver(void); ///< Build the ParamEntry resolver maps
public:
ParamListStandard(void) {} ///< Construct for use with restoreXml()
ParamListStandard(const ParamListStandard &op2); ///< Copy constructor
virtual ~ParamListStandard(void);
const list<ParamEntry> &getEntry(void) const { return entry; } ///< Get the list of parameter entries
virtual uint4 getType(void) const { return p_standard; }
virtual void assignMap(const vector<Datatype *> &proto,bool isinput,
TypeFactory &typefactory,vector<ParameterPieces> &res) const;
virtual void fillinMap(ParamActive *active) const;
virtual bool checkJoin(const Address &hiaddr,int4 hisize,const Address &loaddr,int4 losize) const;
virtual bool checkSplit(const Address &loc,int4 size,int4 splitpoint) const;
virtual int4 characterizeAsParam(const Address &loc,int4 size) const;
virtual bool possibleParam(const Address &loc,int4 size) const;
virtual bool possibleParamWithSlot(const Address &loc,int4 size,int4 &slot,int4 &slotsize) const;
virtual bool getBiggestContainedParam(const Address &loc,int4 size,VarnodeData &res) const;
virtual bool unjustifiedContainer(const Address &loc,int4 size,VarnodeData &res) const;
virtual OpCode assumedExtension(const Address &addr,int4 size,VarnodeData &res) const;
virtual AddrSpace *getSpacebase(void) const { return spacebase; }
virtual void getRangeList(AddrSpace *spc,RangeList &res) const;
virtual int4 getMaxDelay(void) const { return maxdelay; }
virtual void restoreXml(const Element *el,const AddrSpaceManager *manage,vector<EffectRecord> &effectlist,bool normalstack);
virtual ParamList *clone(void) const;
};
/// \brief A standard model for passing back return values from a function
///
/// This models a resource list of potential storage locations for a return value,
/// at most 1 of which will be chosen for a given function. Order only matters in that the
/// first ParamEntry that fits is used. If no entry fits, the return value is
/// converted to a pointer data-type, storage allocation is attempted again, and the
/// return value is marked as a \e hidden return parameter to inform the input model.
class ParamListStandardOut : public ParamListStandard {
public:
ParamListStandardOut(void) : ParamListStandard() {} ///< Constructor
ParamListStandardOut(const ParamListStandardOut &op2) : ParamListStandard(op2) {} ///< Copy constructor
virtual uint4 getType(void) const { return p_standard_out; }
virtual void assignMap(const vector<Datatype *> &proto,bool isinput,
TypeFactory &typefactory,vector<ParameterPieces> &res) const;
virtual void fillinMap(ParamActive *active) const;
virtual bool possibleParam(const Address &loc,int4 size) const;
virtual void restoreXml(const Element *el,const AddrSpaceManager *manage,vector<EffectRecord> &effectlist,bool normalstack);
virtual ParamList *clone(void) const;
};
/// \brief An unstructured model for passing input parameters to a function.
///
/// This is the \b register model, meaning a collection of registers, any of which
/// can be used to pass a parameter. This is nearly identical to ParamListStandard, but
/// rules banning \e holes are not enforced, any subset of the resource list can be used.
/// This makes sense for executables where parameters follow no conventions or only loose
/// conventions. The assignMap() method may make less sense in this scenario.
class ParamListRegister : public ParamListStandard {
public:
ParamListRegister(void) : ParamListStandard() {} ///< Constructor for use with restoreXml()
ParamListRegister(const ParamListRegister &op2) : ParamListStandard(op2) {} ///< Copy constructor
virtual uint4 getType(void) const { return p_register; }
virtual void fillinMap(ParamActive *active) const;
virtual ParamList *clone(void) const;
};
/// \brief A union of other input parameter passing models
///
/// This model is viewed as a union of a constituent set of resource lists.
/// This allows initial data-flow analysis to proceed when the exact model
/// isn't known. The assignMap() and fillinMap() methods are disabled for
/// instances of this class. The controlling prototype model (ProtoModelMerged)
/// decides from among the constituent ParamList models before these routines
/// need to be invoked.
class ParamListMerged : public ParamListStandard {
public:
ParamListMerged(void) : ParamListStandard() {} ///< Constructor for use with restoreXml
ParamListMerged(const ParamListMerged &op2) : ParamListStandard(op2) {} ///< Copy constructor
void foldIn(const ParamListStandard &op2); ///< Add another model to the union
void finalize(void) { populateResolver(); } ///< Fold-ins are finished, finalize \b this
virtual uint4 getType(void) const { return p_merged; }
virtual void assignMap(const vector<Datatype *> &proto,bool isinput,
TypeFactory &typefactory,vector<ParameterPieces> &res) const {
throw LowlevelError("Cannot assign prototype before model has been resolved"); }
virtual void fillinMap(ParamActive *active) const {
throw LowlevelError("Cannot determine prototype before model has been resolved"); }
virtual ParamList *clone(void) const;
};
/// \brief A \b prototype \b model: a model for passing parameters between functions
///
/// This encompasses both input parameters and return values. It attempts to
/// describe the ABI, Application Binary Interface, of the processor or compiler.
/// Any number of function prototypes (FuncProto) can be implemented under a
/// \b prototype \b model, which represents a static rule set the compiler uses
/// to decide:
/// - Storage locations for input parameters
/// - Storage locations for return values
/// - Expected side-effects of a function on other (non-parameter) registers and storage locations
/// - Behavior of the stack and the stack pointer across function calls
///
/// Major analysis concerns are:
/// - Recovering function prototypes from data-flow information: deriveInputMap() and deriveOutputMap()
/// - Calculating parameter storage locations given a function prototype: assignParameterStorage()
/// - Behavior of data-flow around call sites
///
/// A prototype model supports the concept of \b extrapop, which is defined as the change in
/// value of the stack pointer (or the number of bytes popped from the stack) across a call.
/// This value is calculated starting from the point of the p-code CALL or CALLIND op, when the
/// stack parameters have already been pushed by the calling function. So \e extrapop only reflects
/// changes made by the callee.
class ProtoModel {
friend class ProtoModelMerged;
Architecture *glb; ///< The Architecture owning this prototype model
string name; ///< Name of the model
int4 extrapop; ///< Extra bytes popped from stack
ParamList *input; ///< Resource model for input parameters
ParamList *output; ///< Resource model for output parameters
vector<EffectRecord> effectlist; ///< List of side-effects
vector<VarnodeData> likelytrash; ///< Storage locations potentially carrying \e trash values
int4 injectUponEntry; ///< Id of injection to perform at beginning of function (-1 means not used)
int4 injectUponReturn; ///< Id of injection to perform after a call to this function (-1 means not used)
RangeList localrange; ///< Memory range(s) of space-based locals
RangeList paramrange; ///< Memory range(s) of space-based parameters
bool stackgrowsnegative; ///< True if stack parameters have (normal) low address to high address ordering
bool hasThis; ///< True if this model has a \b this parameter (auto-parameter)
bool isConstruct; ///< True if this model is a constructor for a particular object
void defaultLocalRange(void); ///< Set the default stack range used for local variables
void defaultParamRange(void); ///< Set the default stack range used for input parameters
void buildParamList(const string &strategy); ///< Establish the main resource lists for input and output parameters.
public:
enum {
extrapop_unknown = 0x8000 ///< Reserved extrapop value meaning the function's \e extrapop is unknown
};
ProtoModel(Architecture *g); ///< Constructor for use with restoreXml()
ProtoModel(const string &nm,const ProtoModel &op2); ///< Copy constructor changing the name
virtual ~ProtoModel(void); ///< Destructor
const string &getName(void) const { return name; } ///< Get the name of the prototype model
Architecture *getArch(void) const { return glb; } ///< Get the owning Architecture
uint4 hasEffect(const Address &addr,int4 size) const; ///< Determine side-effect of \b this on the given memory range
int4 getExtraPop(void) const { return extrapop; } ///< Get the stack-pointer \e extrapop for \b this model
void setExtraPop(int4 ep) { extrapop = ep; } ///< Set the stack-pointer \e extrapop
int4 getInjectUponEntry(void) const { return injectUponEntry; } ///< Get the inject \e uponentry id
int4 getInjectUponReturn(void) const { return injectUponReturn; } ///< Get the inject \e uponreturn id
/// \brief Given a list of input \e trials, derive the most likely input prototype
///
/// Trials are sorted and marked as \e used or not.
/// \param active is the collection of Varnode input trials
void deriveInputMap(ParamActive *active) const {
input->fillinMap(active); }
/// \brief Given a list of output \e trials, derive the most likely output prototype
///
/// One trial (at most) is marked \e used and moved to the front of the list
/// \param active is the collection of output trials
void deriveOutputMap(ParamActive *active) const {
output->fillinMap(active); }
void assignParameterStorage(const vector<Datatype *> &typelist,vector<ParameterPieces> &res,bool ignoreOutputError);
/// \brief Check if the given two input storage locations can represent a single logical parameter
///
/// Within the conventions of this model, do the two (hi/lo) locations represent
/// consecutive input parameter locations that can be replaced by a single logical parameter.
/// \param hiaddr is the address of the most significant part of the value
/// \param hisize is the size of the most significant part in bytes
/// \param loaddr is the address of the least significant part of the value
/// \param losize is the size of the least significant part in bytes
/// \return \b true if the two pieces can be joined
bool checkInputJoin(const Address &hiaddr,int4 hisize,const Address &loaddr,int4 losize) const {
return input->checkJoin(hiaddr,hisize,loaddr,losize); }
/// \brief Check if the given two output storage locations can represent a single logical return value
///
/// Within the conventions of this model, do the two (hi/lo) locations represent
/// consecutive locations that can be replaced by a single logical return value.
/// \param hiaddr is the address of the most significant part of the value
/// \param hisize is the size of the most significant part in bytes
/// \param loaddr is the address of the least significant part of the value
/// \param losize is the size of the least significant part in bytes
/// \return \b true if the two pieces can be joined
bool checkOutputJoin(const Address &hiaddr,int4 hisize,const Address &loaddr,int4 losize) const {
return output->checkJoin(hiaddr,hisize,loaddr,losize); }
/// \brief Check if it makes sense to split a single storage location into two input parameters
///
/// A storage location and split point is provided, implying two new storage locations. Does
/// \b this model allow these locations to be considered separate parameters.
/// \param loc is the starting address of provided storage location
/// \param size is the size of the location in bytes
/// \param splitpoint is the number of bytes to consider in the first (in address order) piece
/// \return \b true if the storage location can be split
bool checkInputSplit(const Address &loc,int4 size,int4 splitpoint) const {
return input->checkSplit(loc,size,splitpoint); }
const RangeList &getLocalRange(void) const { return localrange; } ///< Get the range of (possible) local stack variables
const RangeList &getParamRange(void) const { return paramrange; } ///< Get the range of (possible) stack parameters
vector<EffectRecord>::const_iterator effectBegin(void) const { return effectlist.begin(); } ///< Get an iterator to the first EffectRecord
vector<EffectRecord>::const_iterator effectEnd(void) const { return effectlist.end(); } ///< Get an iterator to the last EffectRecord
int4 numLikelyTrash(void) const { return likelytrash.size(); } ///< Get the number of \e likelytrash locations
const VarnodeData &getLikelyTrash(int4 i) const { return likelytrash[i]; } ///< Get the i-th \e likelytrashh location
/// \brief Characterize whether the given range overlaps parameter storage
///
/// Does the range naturally fit inside a potential parameter entry from this model or does
/// it contain a parameter entry. Return one of three values indicating this characterization:
/// - 0 means there is no intersection between the range and any ParamEntry
/// - 1 means that at least one ParamEntry contains the range in a properly justified manner
/// - 2 means no ParamEntry contains the range, but the range contains at least one ParamEntry
/// \param loc is the starting address of the given range
/// \param size is the number of bytes in the given range
/// \return the characterization code
int4 characterizeAsInputParam(const Address &loc,int4 size) const {
return input->characterizeAsParam(loc, size);
}
/// \brief Does the given storage location make sense as an input parameter
///
/// Within \b this model, decide if the storage location can be considered an input parameter.
/// \param loc is the starting address of the storage location
/// \param size is the number of bytes in the storage location
/// \return \b true if the location can be a parameter
bool possibleInputParam(const Address &loc,int4 size) const {
return input->possibleParam(loc,size); }
/// \brief Does the given storage location make sense as a return value
///
/// Within \b this model, decide if the storage location can be considered an output parameter.
/// \param loc is the starting address of the storage location
/// \param size is the number of bytes in the storage location
/// \return \b true if the location can be a parameter
bool possibleOutputParam(const Address &loc,int4 size) const {
return output->possibleParam(loc,size); }
/// \brief Pass-back the slot and slot size for the given storage location as an input parameter
///
/// This checks if the given storage location acts as an input parameter in \b this model and
/// passes back the number of slots that it occupies.
/// \param loc is the starting address of the storage location
/// \param size is the number of bytes in the storage location
/// \param slot if the \e slot number to pass back
/// \param slotsize is the number of consumed slots to pass back
/// \return \b true if the location can be a parameter
bool possibleInputParamWithSlot(const Address &loc,int4 size,int4 &slot,int4 &slotsize) const {
return input->possibleParamWithSlot(loc,size,slot,slotsize); }
/// \brief Pass-back the slot and slot size for the given storage location as a return value
///
/// This checks if the given storage location acts as an output parameter in \b this model and
/// passes back the number of slots that it occupies.
/// \param loc is the starting address of the storage location
/// \param size is the number of bytes in the storage location
/// \param slot if the \e slot number to pass back
/// \param slotsize is the number of consumed slots to pass back
/// \return \b true if the location can be a parameter
bool possibleOutputParamWithSlot(const Address &loc,int4 size,int4 &slot,int4 &slotsize) const {
return output->possibleParamWithSlot(loc,size,slot,slotsize); }
/// \brief Check if the given storage location looks like an \e unjustified input parameter
///
/// The storage for a value may be contained in a normal parameter location but be
/// unjustified within that container, i.e. the least significant bytes are not being used.
/// If this is the case, pass back the full parameter location and return \b true.
/// \param loc is the starting address of the given storage
/// \param size is the number of bytes in the given storage
/// \param res is the full parameter storage to pass back
/// \return \b true if the given storage is unjustified within its parameter container
bool unjustifiedInputParam(const Address &loc,int4 size,VarnodeData &res) const {
return input->unjustifiedContainer(loc,size,res); }
/// \brief Get the type of extension and containing input parameter for the given storage
///
/// If the given storage is properly contained within a normal parameter and the model
/// typically extends a small value into the full container, pass back the full container
/// and the type of extension.
/// \param addr is the starting address of the given storage
/// \param size is the number of bytes in the given storage
/// \param res is the parameter storage to pass back
/// \return the extension operator (INT_ZEXT INT_SEXT) or INT_COPY if there is no extension.
/// INT_PIECE indicates the extension is determined by the specific prototype.
OpCode assumedInputExtension(const Address &addr,int4 size,VarnodeData &res) const {
return input->assumedExtension(addr,size,res); }
/// \brief Get the type of extension and containing return value location for the given storage
///
/// If the given storage is properly contained within a normal return value location and the model
/// typically extends a small value into the full container, pass back the full container
/// and the type of extension.
/// \param addr is the starting address of the given storage
/// \param size is the number of bytes in the given storage
/// \param res is the parameter storage to pass back
/// \return the extension operator (INT_ZEXT INT_SEXT) or INT_COPY if there is no extension.
/// INT_PIECE indicates the extension is determined by the specific prototype.
OpCode assumedOutputExtension(const Address &addr,int4 size,VarnodeData &res) const {
return output->assumedExtension(addr,size,res); }
/// \brief Pass-back the biggest input parameter contained within the given range
///
/// \param loc is the starting address of the given range
/// \param size is the number of bytes in the range
/// \param res will hold the parameter storage description being passed back
/// \return \b true if there is at least one parameter contained in the range
bool getBiggestContainedInputParam(const Address &loc,int4 size,VarnodeData &res) const {
return input->getBiggestContainedParam(loc, size, res);
}
AddrSpace *getSpacebase(void) const { return input->getSpacebase(); } ///< Get the stack space associated with \b this model
bool isStackGrowsNegative(void) const { return stackgrowsnegative; } ///< Return \b true if the stack \e grows toward smaller addresses
bool hasThisPointer(void) const { return hasThis; } ///< Is \b this a model for (non-static) class methods
bool isConstructor(void) const { return isConstruct; } ///< Is \b this model for class constructors
/// \brief Return the maximum heritage delay across all possible input parameters
///
/// Depending on the address space, data-flow for a parameter may not be available until
/// extra transform passes have completed. This method returns the number of passes
/// that must occur before we can guarantee that all parameters have data-flow info.
/// \return the maximum number of passes across all input parameters in \b this model
int4 getMaxInputDelay(void) const { return input->getMaxDelay(); }
/// \brief Return the maximum heritage delay across all possible return values
///
/// Depending on the address space, data-flow for a parameter may not be available until
/// extra transform passes have completed. This method returns the number of passes
/// that must occur before we can guarantee that any return value has data-flow info.
/// \return the maximum number of passes across all output parameters in \b this model
int4 getMaxOutputDelay(void) const { return output->getMaxDelay(); }
virtual bool isMerged(void) const { return false; } ///< Is \b this a merged prototype model
virtual void restoreXml(const Element *el); ///< Restore \b this model from an XML stream
static uint4 lookupEffect(const vector<EffectRecord> &efflist,const Address &addr,int4 size);
};
/// \brief Class for calculating "goodness of fit" of parameter trials against a prototype model
///
/// The class is instantiated with a prototype model (ProtoModel). A set of Varnode parameter trials
/// are registered by calling addParameter() for each trial. Then calling doScore() computes a score
/// that evaluates how well the set of registered trials fit the prototype model. A lower score
/// indicates a better fit.
class ScoreProtoModel {
/// \brief A record mapping trials to parameter entries in the prototype model
class PEntry {
public:
int4 origIndex; ///< Original index of trial
int4 slot; ///< Matching slot within the resource list
int4 size; ///< Number of slots occupied
/// \brief Compare PEntry objects by slot
///
/// \param op2 is the PEntry to compare \b this to
/// \return \b true if \b this should be ordered before the other PEntry
bool operator<(const PEntry &op2) const { return (slot < op2.slot); }
};
bool isinputscore; ///< True if scoring against input parameters, \b false for outputs
vector<PEntry> entry; ///< Map of parameter entries corresponding to trials
const ProtoModel *model; ///< Prototype model to score against
int4 finalscore; ///< The final fitness score
int4 mismatch; ///< Number of trials that don't fit the prototype model at all
public:
ScoreProtoModel(bool isinput,const ProtoModel *mod,int4 numparam); ///< Constructor
void addParameter(const Address &addr,int4 sz); ///< Register a trial to be scored
void doScore(void); ///< Compute the fitness score
int4 getScore(void) const { return finalscore; } ///< Get the fitness score
int4 getNumMismatch(void) const { return mismatch; } ///< Get the number of mismatched trials
};
/// \brief A prototype model made by merging together other models
///
/// This model serves as a placeholder for multiple models, when the exact model
/// hasn't been immediately determined. At the time of active parameter recovery
/// the correct model is selected for the given set of trials
/// from among the constituent prototype models used to build \b this,
/// by calling the method selectModel().
/// Up to this time, \b this serves as a merged form of the models
/// so that all potential parameter trials will be included in the analysis. The parameter recovery
/// for the output part of the model is currently limited, so the constituent models must all share
/// the same output model, and this part is \e not currently merged.
class ProtoModelMerged : public ProtoModel {
vector<ProtoModel *> modellist; ///< Constituent models being merged
void intersectEffects(const vector<EffectRecord> &efflist); ///< Fold EffectRecords into \b this model
void intersectLikelyTrash(const vector<VarnodeData> &trashlist); ///< Fold \e likelytrash locations into \b this model
public:
ProtoModelMerged(Architecture *g) : ProtoModel(g) {} ///< Constructor
virtual ~ProtoModelMerged(void) {} ///< Destructor
int4 numModels(void) const { return modellist.size(); } ///< Get the number of constituent models
ProtoModel *getModel(int4 i) const { return modellist[i]; } ///< Get the i-th model
void foldIn(ProtoModel *model); ///< Fold-in an additional prototype model
ProtoModel *selectModel(ParamActive *active) const; ///< Select the best model given a set of trials
virtual bool isMerged(void) const { return true; }
virtual void restoreXml(const Element *el);
};
class Symbol;
class AliasChecker;
/// \brief A function parameter viewed as a name, data-type, and storage address
///
/// This is the base class, with derived classes determining what is backing up
/// the information, whether is it a formal Symbol or just internal storage.
/// Both input parameters and return values can be represented with this object.
class ProtoParameter {
public:
ProtoParameter(void) {} ///< Constructor
virtual ~ProtoParameter(void) {} ///< Destructor
virtual const string &getName(void) const=0; ///< Get the name of the parameter ("" for return value)
virtual Datatype *getType(void) const=0; ///< Get the data-type associate with \b this
virtual Address getAddress(void) const=0; ///< Get the storage address for \b this parameter
virtual int4 getSize(void) const=0; ///< Get the number of bytes occupied by \b this parameter
virtual bool isTypeLocked(void) const=0; ///< Is the parameter data-type locked
virtual bool isNameLocked(void) const=0; ///< Is the parameter name locked
virtual bool isSizeTypeLocked(void) const=0; ///< Is the size of the parameter locked
virtual bool isIndirectStorage(void) const=0; ///< Is \b this really a pointer to the true parameter
virtual bool isHiddenReturn(void) const=0; ///< Is \b this a pointer to storage for a return value
virtual bool isNameUndefined(void) const=0; ///< Is the name of \b this parameter undefined
virtual void setTypeLock(bool val)=0; ///< Toggle the lock on the data-type
virtual void setNameLock(bool val)=0; ///< Toggle the lock on the name
/// \brief Change (override) the data-type of a \e size-locked parameter.
///
/// The original parameter must have a \e type-lock and TYPE_UNKNOWN data-type.
/// The \e size-lock is preserved and \b this can be cleared back to its TYPE_UNKNOWN state.
/// \param ct is the overriding data-type
virtual void overrideSizeLockType(Datatype *ct)=0;
/// \brief Clear \b this parameter's data-type preserving any \e size-lock
///
/// The data-type is converted to a TYPE_UNKNOWN of the same size
/// \param factory is the TypeFactory that will construct the unknown data-type
virtual void resetSizeLockType(TypeFactory *factory)=0;
virtual ProtoParameter *clone(void) const=0; ///< Clone the parameter
/// \brief Retrieve the formal Symbol associated with \b this parameter
///
/// If there is no backing symbol an exception is thrown
/// \return the backing Symbol object
virtual Symbol *getSymbol(void) const=0;
/// \brief Compare storage location and data-type for equality
///
/// \param op2 is the parameter to compare with \b this
/// \return \b true if the parameters share a data-type and storage location
bool operator==(const ProtoParameter &op2) const {
if (getAddress() != op2.getAddress()) return false;
if (getType() != op2.getType()) return false;
return true;
}
/// \brief Compare storage location and data-type for inequality
///
/// \param op2 is the parameter to compare with \b this
/// \return \b true if the parameters do not share a data-type and storage location
bool operator!=(const ProtoParameter &op2) const {
return !(*this==op2); }
};
/// \brief A stand-alone parameter with no backing symbol
///
/// Name, data-type, and storage location is stored internally to the object.
/// This is suitable for return values, function pointer prototypes, or functions
/// that haven't been fully analyzed.
class ParameterBasic : public ProtoParameter {
string name; ///< The name of the parameter, "" for undefined or return value parameters
Address addr; ///< Storage address of the parameter
Datatype *type; ///< Data-type of the parameter
uint4 flags; ///< Lock properties. Varnode::mark is co-opted to hold the \e size-lock flag
public:
ParameterBasic(const string &nm,const Address &ad,Datatype *tp,uint4 fl) {
name = nm; addr = ad; type = tp; flags=fl; } ///< Construct from components
virtual const string &getName(void) const { return name; }
virtual Datatype *getType(void) const { return type; }
virtual Address getAddress(void) const { return addr; }
virtual int4 getSize(void) const { return type->getSize(); }
virtual bool isTypeLocked(void) const { return ((flags&Varnode::typelock)!=0); }
virtual bool isNameLocked(void) const { return ((flags&Varnode::namelock)!=0); }
virtual bool isSizeTypeLocked(void) const { return ((flags&Varnode::mark)!=0); }
virtual bool isIndirectStorage(void) const { return ((flags&Varnode::indirectstorage)!=0); }
virtual bool isHiddenReturn(void) const { return ((flags&Varnode::hiddenretparm)!=0); }
virtual bool isNameUndefined(void) const { return (name.size()==0); }
virtual void setTypeLock(bool val);
virtual void setNameLock(bool val);
virtual void overrideSizeLockType(Datatype *ct);
virtual void resetSizeLockType(TypeFactory *factory);
virtual ProtoParameter *clone(void) const;
virtual Symbol *getSymbol(void) const { throw LowlevelError("Parameter is not a real symbol"); }
};
/// \brief A collection parameter descriptions making up a function prototype
///
/// A unified interface for accessing descriptions of individual
/// parameters in a function prototype. Both input parameters and return values
/// are described.
class ProtoStore {
public:
virtual ~ProtoStore(void) {} ///< Constructor
/// \brief Establish name, data-type, storage of a specific input parameter
///