sleigh-sys 0.1.0

Rust bindings for Ghidra's Sleigh decompiler
Documentation
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
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
/* ###
 * 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
    is_grouped = 512		///< This entry is grouped with other entries
  };
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
  static const ParamEntry *findEntryByStorage(const list<ParamEntry> &entryList,const VarnodeData &vn);
  void resolveJoin(list<ParamEntry> &curList); 	///< Make adjustments for a \e join ParamEntry

  /// \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
  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 isGrouped(void) const { return ((flags & is_grouped)!=0); }	///< Return \b true if \b this is grouped with other entries
  bool isNonOverlappingJoin(void) const;	///< Return \b true if not all pieces overlap other ParamEntry tags
  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,bool grouped,list<ParamEntry> &curList);
  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
  int4 countJoinOverlap(const list<ParamEntry> &curList) const;		///< Count the number of other entries \b this overlaps
  static void orderWithinGroup(const ParamEntry &entry1,const ParamEntry &entry2);	///< Enforce ParamEntry group ordering rules
};

/// \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(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,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);
  static const string NAME;		///< Reserved name for the fspec space
};

/// \brief Basic elements of a parameter: address, data-type, properties
struct ParameterPieces {
  enum {
    isthis = 1,		///< Parameter is "this" pointer
    hiddenretparm = 2,	///< Parameter is hidden pointer to return value, mirrors Varnode::hiddenretparm
    indirectstorage = 4,	///< Parameter is indirect pointer to true parameter, mirrors Varnode::indirectstorage
    namelock = 8,	///< Parameter's name is locked, mirrors Varnode::namelock
    typelock = 16,	///< Parameter's data-type is locked, mirrors Varnode::typelock
    sizelock = 32	///< Size of the parameter is locked (but not the data-type)
  };
  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 store the return address
    unknown_effect = 4	///< An unknown effect (indicates the absence of an EffectRecord)
  };
private:
  VarnodeData range;		///< The memory range affected
  uint4 type;			///< The type of effect
public:
  EffectRecord(void) {}		///< Constructor for use with restoreXml()
  EffectRecord(const EffectRecord &op2) { range = op2.range; 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(range.space,range.offset); }	///< Get the starting address of the affected range
  int4 getSize(void) const { return range.size; }	///< Get the size of the affected range
  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
  static bool compareByAddress(const EffectRecord &op1,const EffectRecord &op2);
};

/// 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_register_out,	///< Multiple possible return value 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 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,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 resourceTwoStart;		///< If there are two resource sections, the group of the first entry in the second section
  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 separateSections(ParamActive *active,int4 &oneStart,int4 &oneStop,int4 &twoStart,int4 &twoStop) 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,int4 groupstart) const;
  void calcDelay(void);		///< Calculate the maximum heritage delay for any potential parameter in this list
  void populateResolver(void);	///< Build the ParamEntry resolver maps
  void parsePentry(const Element *el,const AddrSpaceManager *manage,vector<EffectRecord> &effectlist,
		   int4 groupid,bool normalstack,bool autokill,bool splitFloat,bool grouped);
  void parseGroup(const Element *el,const AddrSpaceManager *manage,vector<EffectRecord> &effectlist,
		  int4 groupid,bool normalstack,bool autokill,bool splitFloat);
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,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 model for passing back return values from a function
///
/// This is a resource list of potential storage locations for a return value,
/// at most 1 of which will be chosen for a given function. This models a simple strategy
/// for selecting a storage location. When assigning based on data-type (assignMap), the first list
/// entry that fits is chosen.  When assigning from a set of actively used locations (fillinMap),
/// this class chooses the location that is the closest fitting match to an entry in the resource list.
class ParamListRegisterOut : public ParamListStandard {
public:
  ParamListRegisterOut(void) : ParamListStandard() {}		///< Constructor
  ParamListRegisterOut(const ParamListRegisterOut &op2) : ParamListStandard(op2) {}	///< Copy constructor
  virtual uint4 getType(void) const { return p_register_out; }
  virtual void assignMap(const vector<Datatype *> &proto,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 standard model for returning output parameters from a function
///
/// This has a more involved assignment strategy than its parent class.
/// Entries in the resource list are treated as a \e group, meaning that only one can
/// fit the desired storage size and type attributes of the return value. 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 ParamListRegisterOut {
public:
  ParamListStandardOut(void) : ParamListRegisterOut() {}	///< Constructor for use with restoreXml()
  ParamListStandardOut(const ParamListStandardOut &op2) : ParamListRegisterOut(op2) {}	///< Copy constructor
  virtual uint4 getType(void) const { return p_standard_out; }
  virtual void assignMap(const vector<Datatype *> &proto,TypeFactory &typefactory,vector<ParameterPieces> &res) const;
  virtual void restoreXml(const Element *el,const AddrSpaceManager *manage,vector<EffectRecord> &effectlist,bool normalstack);
  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,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
  const ProtoModel *compatModel;	///< The model \b this is a copy of
  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
  bool isCompatible(const ProtoModel *op2) const;	///< Return \b true if other given model can be substituted for \b this

  /// \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
  vector<VarnodeData>::const_iterator trashBegin(void) const { return likelytrash.begin(); }	///< Get an iterator to the first \e likelytrash
  vector<VarnodeData>::const_iterator trashEnd(void) const { return likelytrash.end(); }	///< Get an iterator to the last \e likelytrash
  /// \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);
  static int4 lookupRecord(const vector<EffectRecord> &efflist,int4 listSize,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 isThisPointer(void) const=0;		///< Is \b this the "this" pointer for a class method
  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
  virtual void setThisPointer(bool val)=0;		///< Toggle whether \b this is the "this" pointer for a class method

  /// \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 and other properties from ParameterPieces flags
public:
  ParameterBasic(const string &nm,const Address &ad,Datatype *tp,uint4 fl) {
    name = nm; addr = ad; type = tp; flags=fl; }		///< Construct from components
  ParameterBasic(Datatype *tp) {
    type = tp; flags = 0; }			///< Construct a \e void parameter
  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&ParameterPieces::typelock)!=0); }
  virtual bool isNameLocked(void) const { return ((flags&ParameterPieces::namelock)!=0); }
  virtual bool isSizeTypeLocked(void) const { return ((flags&ParameterPieces::sizelock)!=0); }
  virtual bool isThisPointer(void) const { return ((flags&ParameterPieces::isthis)!=0); }
  virtual bool isIndirectStorage(void) const { return ((flags&ParameterPieces::indirectstorage)!=0); }
  virtual bool isHiddenReturn(void) const { return ((flags&ParameterPieces::hiddenretparm)!=0); }
  virtual bool isNameUndefined(void) const { return (name.size()==0); }
  virtual void setTypeLock(bool val);
  virtual void setNameLock(bool val);
  virtual void setThisPointer(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
  ///
  /// This either allocates a new parameter or replaces the existing one at the
  /// specified input slot.  If there is a backing symbol table, a Symbol is
  /// created or modified.
  /// \param i is the specified input slot
  /// \param nm is the (optional) name of the parameter
  /// \param pieces holds the raw storage address and data-type to set
  /// \return the new/modified ProtoParameter
  virtual ProtoParameter *setInput(int4 i,const string &nm,const ParameterPieces &pieces)=0;

  /// \brief Clear the input parameter at the specified slot
  ///
  /// The parameter is excised, any following parameters are shifted to fill its spot.
  /// If there is a backing Symbol, it is removed from the SymbolTable
  /// \param i is the specified parameter slot to remove
  virtual void clearInput(int4 i)=0;

  virtual void clearAllInputs(void)=0;			///< Clear all input parameters (and any backing symbols)
  virtual int4 getNumInputs(void) const=0;		///< Get the number of input parameters for \b this prototype
  virtual ProtoParameter *getInput(int4 i)=0;		///< Get the i-th input parameter (or NULL if it doesn't exist)

  /// \brief Establish the data-type and storage of the return value
  ///
  /// This either allocates a new parameter or replaces the existing one.
  /// A \e void return value can be specified with an \e invalid address and TYPE_VOID data-type.
  /// \param piece holds the raw storage address and data-type to set
  /// \return the new/modified ProtoParameter
  virtual ProtoParameter *setOutput(const ParameterPieces &piece)=0;

  virtual void clearOutput(void)=0;			///< Clear the return value to TYPE_VOID
  virtual ProtoParameter *getOutput(void)=0;		///< Get the return-value description
  virtual ProtoStore *clone(void) const=0;		///< Clone the entire collection of parameter descriptions

  /// \brief Save any parameters that are not backed by symbols to an XML stream
  ///
  /// Symbols are stored elsewhere, so symbol backed parameters are not serialized.
  /// If there are any internal parameters an \<internallist> tag is emitted.
  /// \param s is the output stream
  virtual void saveXml(ostream &s) const=0;

  /// \brief Restore any internal parameter descriptions from an XML stream
  ///
  /// \param el is a root \<internallist> element containing \<param> and \<retparam> sub-tags.
  /// \param model is prototype model for determining storage for unassigned parameters
  virtual void restoreXml(const Element *el,ProtoModel *model)=0;
};

/// \brief A parameter with a formal backing Symbol
///
/// Input parameters generally have a symbol associated with them.
/// This class holds a reference to the Symbol object and pulls the relevant
/// parameter information off of it.
class ParameterSymbol : public ProtoParameter {
  friend class ProtoStoreSymbol;
  Symbol *sym;		///< Backing Symbol for \b this parameter
public:
  ParameterSymbol(void) { sym = (Symbol *)0; }		///< Constructor
  virtual const string &getName(void) const;
  virtual Datatype *getType(void) const;
  virtual Address getAddress(void) const;
  virtual int4 getSize(void) const;
  virtual bool isTypeLocked(void) const;
  virtual bool isNameLocked(void) const;
  virtual bool isSizeTypeLocked(void) const;
  virtual bool isThisPointer(void) const;
  virtual bool isIndirectStorage(void) const;
  virtual bool isHiddenReturn(void) const;
  virtual bool isNameUndefined(void) const;
  virtual void setTypeLock(bool val);
  virtual void setNameLock(bool val);
  virtual void setThisPointer(bool val);
  virtual void overrideSizeLockType(Datatype *ct);
  virtual void resetSizeLockType(TypeFactory *factory);
  virtual ProtoParameter *clone(void) const;
  virtual Symbol *getSymbol(void) const;
};

/// \brief A collection of parameter descriptions backed by Symbol information
///
/// Input parameters are determined by symbols a function Scope
/// (category 0).  Information about the return-value is stored internally.
/// ProtoParameter objects are constructed on the fly as requested and cached.
class ProtoStoreSymbol : public ProtoStore {
  Scope *scope;				///< Backing Scope for input parameters
  Address restricted_usepoint;		///< A usepoint reference for storage locations (usually function entry -1)
  vector<ProtoParameter *> inparam;	///< Cache of allocated input parameters
  ProtoParameter *outparam;		///< The return-value parameter
  ParameterSymbol *getSymbolBacked(int4 i);	///< Fetch or allocate the parameter for the indicated slot
public:
  ProtoStoreSymbol(Scope *sc,const Address &usepoint);	///< Constructor
  virtual ~ProtoStoreSymbol(void);
  virtual ProtoParameter *setInput(int4 i,const string &nm,const ParameterPieces &pieces);
  virtual void clearInput(int4 i);
  virtual void clearAllInputs(void);
  virtual int4 getNumInputs(void) const;
  virtual ProtoParameter *getInput(int4 i);
  virtual ProtoParameter *setOutput(const ParameterPieces &piece);
  virtual void clearOutput(void);
  virtual ProtoParameter *getOutput(void);
  virtual ProtoStore *clone(void) const;
  virtual void saveXml(ostream &s) const;
  virtual void restoreXml(const Element *el,ProtoModel *model);
};

/// \brief A collection of parameter descriptions without backing symbols
///
/// Parameter descriptions are stored internally to the object and are not
/// mirrored by a symbol table.
class ProtoStoreInternal : public ProtoStore {
  Datatype *voidtype;			///< Cached reference to the \b void data-type
  vector<ProtoParameter *> inparam;	///< Descriptions of input parameters
  ProtoParameter *outparam;		///< Description of the return value
public:
  ProtoStoreInternal(Datatype *vt);	///< Constructor
  virtual ~ProtoStoreInternal(void);
  virtual ProtoParameter *setInput(int4 i,const string &nm,const ParameterPieces &pieces);
  virtual void clearInput(int4 i);
  virtual void clearAllInputs(void);
  virtual int4 getNumInputs(void) const;
  virtual ProtoParameter *getInput(int4 i);
  virtual ProtoParameter *setOutput(const ParameterPieces &piece);
  virtual void clearOutput(void);
  virtual ProtoParameter *getOutput(void);
  virtual ProtoStore *clone(void) const;
  virtual void saveXml(ostream &s) const;
  virtual void restoreXml(const Element *el,ProtoModel *model);
};

/// \brief Raw components of a function prototype (obtained from parsing source code)
struct PrototypePieces {
  ProtoModel *model;		///< (Optional) model on which prototype is based
  string name;			///< Identifier (function name) associated with prototype
  Datatype *outtype;		///< Return data-type
  vector<Datatype *> intypes;	///< Input data-types
  vector<string> innames;	///< Identifiers for input types
  bool dotdotdot;		///< True if prototype takes variable arguments
};

/// \brief A \b function \b prototype
///
/// A description of the parameters and return value for a specific function.
/// Parameter descriptions include both source code features like \e name and \e data-type
/// but also give the storage location. Storage follows a specific parameter passing convention
/// (ProtoModel), although individual parameters may be customized.  The prototype describes
/// numerous properties related to calling the specific function:
///   - Side-effects on non-parameter storage locations (like save registers)
///   - P-code injection associated with the function (uponentry, uponreturn, callfixup)
///   - Additional bytes (\b extrapop) popped from the stack by the function
///   - Method flags (thiscall, is_constructor, is_destructor)
class FuncProto {
  enum {
    dotdotdot = 1,		///< Set if \b this prototype takes variable arguments (varargs)
    voidinputlock = 2,		///< Set if \b this prototype takes no inputs and is locked
    modellock = 4,		///< Set if the PrototypeModel is locked for \b this prototype
    is_inline = 8,		///< Should \b this be inlined (within calling function) by decompiler
    no_return = 16,		///< Function does not return
    paramshift_applied = 32,	///< paramshift parameters have been added and removed
    error_inputparam = 64,	///< Set if the input parameters are not properly represented
    error_outputparam = 128,	///< Set if the return value(s) are not properly represented
    custom_storage = 256,	///< Parameter storage is custom (not derived from ProtoModel)
    unknown_model = 512,	///< Set if the PrototypeModel isn't known
    is_constructor = 0x400,	///< Function is an (object-oriented) constructor
    is_destructor = 0x800,	///< Function is an (object-oriented) destructor
    has_thisptr= 0x1000,	///< Function is a method with a 'this' pointer as an argument
    is_override = 0x2000	///< Set if \b this prototype is created to override a single call site
  };
  ProtoModel *model;		///< Model of for \b this prototype
  ProtoStore *store;		///< Storage interface for parameters
  int4 extrapop;		///< Extra bytes popped from stack
  uint4 flags;			///< Boolean properties of the function prototype
  vector<EffectRecord> effectlist;	///< Side-effects associated with non-parameter storage locations
  vector<VarnodeData> likelytrash;	///< Locations that may contain \e trash values
  int4 injectid;		///< (If non-negative) id of p-code snippet that should replace this function
  int4 returnBytesConsumed;	///< Number of bytes of return value that are consumed by callers (0 = all bytes)
  void updateThisPointer(void);	///< Make sure any "this" parameter is properly marked
  void saveEffectXml(ostream &s) const;		///< Save any overriding EffectRecords to XML stream
  void saveLikelyTrashXml(ostream &s) const;	///< Save any overriding likelytrash registers to XML stream
  void restoreEffectXml(void);	///< Merge in any EffectRecord overrides
  void restoreLikelyTrashXml(void);	///< Merge in any \e likelytrash overrides
protected:
  void paramShift(int4 paramshift);	///< Add parameters to the front of the input parameter list
  bool isParamshiftApplied(void) const { return ((flags&paramshift_applied)!=0); }	///< Has a parameter shift been applied
  /// \brief Toggle whether a parameter shift has been applied
  void setParamshiftApplied(bool val) { flags = val ? (flags|paramshift_applied) : (flags & ~((uint4)paramshift_applied)); }
public:
  FuncProto(void);		///< Constructor
  ~FuncProto(void);		///< Destructor
  Architecture *getArch(void) const { return model->getArch(); }	///< Get the Architecture owning \b this
  void copy(const FuncProto &op2);					///< Copy another function prototype
  void copyFlowEffects(const FuncProto &op2);	 			///< Copy properties that affect data-flow
  void getPieces(PrototypePieces &pieces) const;			///< Get the raw pieces of the prototype
  void setPieces(const PrototypePieces &pieces);			///< Set \b this prototype based on raw pieces
  void setScope(Scope *s,const Address &startpoint);			///< Set a backing symbol Scope for \b this
  void setInternal(ProtoModel *m,Datatype *vt);				///< Set internal backing storage for \b this
  void setModel(ProtoModel *m);						///< Set the prototype model for \b this
  bool hasModel(void) const { return (model != (ProtoModel *)0); }	///< Does \b this prototype have a model

  bool hasMatchingModel(const FuncProto *op2) const { return (model == op2->model); }	///< Does \b this have a matching model
  bool hasMatchingModel(const ProtoModel *op2) const { return (model == op2); }	///< Does \b this use the given model
  const string &getModelName(void) const { return model->getName(); }	///< Get the prototype model name
  int4 getModelExtraPop(void) const { return model->getExtraPop(); }	///< Get the \e extrapop of the prototype model

  bool isInputLocked(void) const;					///< Are input data-types locked
  bool isOutputLocked(void) const { return store->getOutput()->isTypeLocked(); }	///< Is the output data-type locked
  bool isModelLocked(void) const { return ((flags&modellock)!=0); }	///< Is the prototype model for \b this locked
  bool isUnknownModel(void) const { return ((flags&unknown_model)!=0); }	///< Is prototype model officially "unknown"
  bool hasCustomStorage(void) const { return ((flags&custom_storage)!=0); }	///< Is \b this a "custom" function prototype
  void setInputLock(bool val);				///< Toggle the data-type lock on input parameters
  void setOutputLock(bool val);				///< Toggle the data-type lock on the return value

  /// \brief Toggle the lock on the prototype model for \b this.
  ///
  /// The prototype model can be locked while still leaving parameters unlocked. Parameter
  /// recovery will follow the rules of the locked model.
  /// \param val is \b true to indicate a lock, \b false for unlocked
  void setModelLock(bool val) { flags = val ? (flags|modellock) : (flags & ~((uint4)modellock)); }

  bool isInline(void) const { return ((flags & is_inline)!=0); }	///< Does this function get \e in-lined during decompilation.

  /// \brief Toggle the \e in-line setting for functions with \b this prototype
  ///
  /// In-lining can be based on a \e call-fixup, or the full body of the function can be in-lined.
  /// \param val is \b true if in-lining should be performed.
  void setInline(bool val) { flags = val ? (flags|is_inline) : (flags & ~((uint4)is_inline)); }

  /// \brief Get the injection id associated with \b this.
  ///
  /// A non-negative id indicates a \e call-fixup is used to in-line function's with \b this prototype.
  /// \return the id value corresponding to the specific call-fixup or -1 if there is no call-fixup
  int4 getInjectId(void) const { return injectid; }

  /// \brief Get an estimate of the number of bytes consumed by callers of \b this prototype.
  ///
  /// A value of 0 means \e all possible bytes of the storage location are consumed.
  /// \return the number of bytes or 0
  int4 getReturnBytesConsumed(void) const { return returnBytesConsumed; }

  bool setReturnBytesConsumed(int4 val);	///< Set the number of bytes consumed by callers of \b this

  /// \brief Does a function with \b this prototype never return
  bool isNoReturn(void) const { return ((flags & no_return)!=0); }

  /// \brief Toggle the \e no-return setting for functions with \b this prototype
  ///
  /// \param val is \b true to treat the function as never returning
  void setNoReturn(bool val) { flags = val ? (flags|no_return) : (flags & ~((uint4)no_return)); }

  /// \brief Is \b this a prototype for a class method, taking a \e this pointer.
  bool hasThisPointer(void) const { return ((flags & has_thisptr)!=0); }

  /// \brief Is \b this prototype for a class constructor method
  bool isConstructor(void) const { return ((flags & is_constructor)!=0); }

  /// \brief Toggle whether \b this prototype is a \e constructor method
  ///
  /// \param val is \b true if \b this is a constructor, \b false otherwise
  void setConstructor(bool val) { flags = val ? (flags|is_constructor) : (flags & ~((uint4)is_constructor)); }

  /// \brief Is \b this prototype for a class destructor method
  bool isDestructor(void) const { return ((flags & is_destructor)!=0); }

  /// \brief Toggle whether \b this prototype is a \e destructor method
  ///
  /// \param val is \b true if \b this is a destructor
  void setDestructor(bool val) { flags = val ? (flags|is_destructor) : (flags & ~((uint4)is_destructor)); }

  /// \brief Has \b this prototype been marked as having an incorrect input parameter descriptions
  bool hasInputErrors(void) const { return ((flags&error_inputparam)!=0); }

  /// \brief Has \b this prototype been marked as having an incorrect return value description
  bool hasOutputErrors(void) const { return ((flags&error_outputparam)!=0); }

  /// \brief Toggle the input error setting for \b this prototype
  ///
  /// \param val is \b true if input parameters should be marked as in error
  void setInputErrors(bool val) { flags = val ? (flags|error_inputparam) : (flags & ~((uint4)error_inputparam)); }

  /// \brief Toggle the output error setting for \b this prototype
  ///
  /// \param val is \b true if return value should be marked as in error
  void setOutputErrors(bool val) { flags = val ? (flags|error_outputparam) : (flags & ~((uint4)error_outputparam)); }

  int4 getExtraPop(void) const { return extrapop; }		///< Get the general \e extrapop setting for \b this prototype
  void setExtraPop(int4 ep) { extrapop = ep; }			///< Set the general \e extrapop for \b this prototype
  int4 getInjectUponEntry(void) const { return model->getInjectUponEntry(); }	///< Get any \e upon-entry injection id (or -1)
  int4 getInjectUponReturn(void) const { return model->getInjectUponReturn(); }	///< Get any \e upon-return injection id (or -1)
  void resolveExtraPop(void);

  void clearUnlockedInput(void);		///< Clear input parameters that have not been locked
  void clearUnlockedOutput(void);		///< Clear the return value if it has not been locked
  void clearInput(void);			///< Clear all input parameters regardless of lock
  void cancelInjectId(void);			///< Turn-off any in-lining for this function

  void resolveModel(ParamActive *active);

  /// \brief Given a list of input \e trials, derive the most likely inputs for \b this 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 {
    model->deriveInputMap(active); }

  /// \brief Given a list of output \e trials, derive the most likely return value for \b this 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 {
    model->deriveOutputMap(active); }

  /// \brief Check if the given two input storage locations can represent a single logical parameter
  ///
  /// For \b this prototype, 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 hisz is the size of the most significant part in bytes
  /// \param loaddr is the address of the least significant part of the value
  /// \param losz 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 hisz,const Address &loaddr,int4 losz) const {
    return model->checkInputJoin(hiaddr,hisz,loaddr,losz); }

  /// \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 prototype 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 model->checkInputSplit(loc,size,splitpoint); }

  void updateInputTypes(Funcdata &data,const vector<Varnode *> &triallist,ParamActive *activeinput);
  void updateInputNoTypes(Funcdata &data,const vector<Varnode *> &triallist,ParamActive *activeinput);
  void updateOutputTypes(const vector<Varnode *> &triallist);
  void updateOutputNoTypes(const vector<Varnode *> &triallist,TypeFactory *factory);
  void updateAllTypes(const vector<string> &namelist,const vector<Datatype *> &typelist,bool dtdtdt);
  ProtoParameter *getParam(int4 i) const { return store->getInput(i); }	///< Get the i-th input parameter
  void removeParam(int4 i) { store->clearInput(i); }		///< Remove the i-th input parameter
  int4 numParams(void) const { return store->getNumInputs(); }	///< Get the number of input parameters
  ProtoParameter *getOutput(void) const { return store->getOutput(); }	///< Get the return value
  Datatype *getOutputType(void) const { return store->getOutput()->getType(); }	///< Get the return value data-type
  const RangeList &getLocalRange(void) const { return model->getLocalRange(); }	///< Get the range of potential local stack variables
  const RangeList &getParamRange(void) const { return model->getParamRange(); }	///< Get the range of potential stack parameters
  bool isStackGrowsNegative(void) const { return model->isStackGrowsNegative(); }	///< Return \b true if the stack grows toward smaller addresses
  bool isDotdotdot(void) const { return ((flags&dotdotdot)!=0); }	///< Return \b true if \b this takes a variable number of arguments
  void setDotdotdot(bool val) { flags = val ? (flags|dotdotdot) : (flags & ~((uint4)dotdotdot)); }	///< Toggle whether \b this takes variable arguments
  bool isOverride(void) const { return ((flags&is_override)!=0); }	///< Return \b true if \b this is a call site override
  void setOverride(bool val) { flags = val ? (flags|is_override) : (flags & ~((uint4)is_override)); }	///< Toggle whether \b this is a call site override
  uint4 hasEffect(const Address &addr,int4 size) const;
  vector<EffectRecord>::const_iterator effectBegin(void) const;	///< Get iterator to front of EffectRecord list
  vector<EffectRecord>::const_iterator effectEnd(void) const;	///< Get iterator to end of EffectRecord list
  vector<VarnodeData>::const_iterator trashBegin(void) const;	///< Get iterator to front of \e likelytrash list
  vector<VarnodeData>::const_iterator trashEnd(void) const;	///< Get iterator to end of \e likelytrash list
  int4 characterizeAsInputParam(const Address &addr,int4 size) const;
  bool possibleInputParam(const Address &addr,int4 size) const;
  bool possibleOutputParam(const Address &addr,int4 size) const;

  /// \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 prototype
  int4 getMaxInputDelay(void) const { return model->getMaxInputDelay(); }

  /// \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 prototype
  int4 getMaxOutputDelay(void) const { return model->getMaxOutputDelay(); }

  bool unjustifiedInputParam(const Address &addr,int4 size,VarnodeData &res) const;

  /// \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 model->assumedInputExtension(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 model->assumedOutputExtension(addr,size,res); }

  /// \brief Pass-back the biggest potential input parameter contained within the given range
  bool getBiggestContainedInputParam(const Address &loc,int4 size,VarnodeData &res) const;

  bool isCompatible(const FuncProto &op2) const;
  AddrSpace *getSpacebase(void) const { return model->getSpacebase(); }		///< Get the \e stack address space
  void printRaw(const string &funcname,ostream &s) const;

  /// \brief Get the comparable properties of \b this prototype
  ///
  /// Get properties not including locking, error, and inlining flags.
  /// \return the active set of flags for \b this prototype
  uint4 getComparableFlags(void) const { return (flags & (dotdotdot | is_constructor | is_destructor | has_thisptr )); }

  void saveXml(ostream &s) const;
  void restoreXml(const Element *el,Architecture *glb);
};

class Funcdata;

/// \brief A class for analyzing parameters to a sub-function call
///
/// This can be viewed as a function prototype that evolves over the course of
/// analysis. It derives off of FuncProto and includes facilities for analyzing
/// data-flow for parameter information. This is the high-level object managing
/// the examination of data-flow to recover a working prototype (ParamActive),
/// holding a stack-pointer placeholder to facilitate stack analysis, and deciding
/// on the working \e extrapop for the CALL.
///
/// A \b stack-pointer \b placeholder is a temporary Varnode in the input operands
/// of the CALL or CALLIND that is defined by a LOAD from the stack-pointer. By examining
/// the pointer, the exact value of the stack-pointer (relative to its incoming value) can
/// be computed at the point of the CALL.  The temporary can arise naturally if stack
/// parameters are a possibility, otherwise a placeholder temporary is artificially
/// inserted into the CALL input.  At the time heritage of the stack space is computed,
/// the placeholder is examined to read off the active stack-pointer offset for the CALL
/// and the placeholder is removed.
class FuncCallSpecs : public FuncProto {
  PcodeOp *op;			///< Pointer to CALL or CALLIND instruction
  string name;			///< Name of function if present
  Address entryaddress;		///< First executing address of function
  Funcdata *fd;			///< The Funcdata object for the called functon (if known)
  int4 effective_extrapop;	///< Working extrapop for the CALL
  uintb stackoffset;		///< Relative offset of stack-pointer at time of this call
  int4 stackPlaceholderSlot;	///< Slot containing temporary stack tracing placeholder (-1 means unused)
  int4 paramshift;		///< Number of input parameters to ignore before prototype
  int4 matchCallCount;		///< Number of calls to this sub-function within the calling function
  ParamActive activeinput;	///< Info for recovering input parameters
  ParamActive activeoutput;	///< Info for recovering output parameters
  mutable vector<int4> inputConsume;	///< Number of bytes consumed by sub-function, for each input parameter
  bool isinputactive; 		///< Are we actively trying to recover input parameters
  bool isoutputactive;		///< Are we actively trying to recover output parameters
  bool isbadjumptable;		///< Was the call originally a jump-table we couldn't recover
  Varnode *getSpacebaseRelative(void) const;	///< Get the active stack-pointer Varnode at \b this call site
  Varnode *buildParam(Funcdata &data,Varnode *vn,ProtoParameter *param,Varnode *stackref);
  int4 transferLockedInputParam(ProtoParameter *param);
  PcodeOp *transferLockedOutputParam(ProtoParameter *param);
  bool transferLockedInput(vector<Varnode *> &newinput);
  bool transferLockedOutput(Varnode *&newoutput);
  void commitNewInputs(Funcdata &data,vector<Varnode *> &newinput);
  void commitNewOutputs(Funcdata &data,Varnode *newout);
  void collectOutputTrialVarnodes(vector<Varnode *> &trialvn);
public:
  enum {
    offset_unknown = 0xBADBEEF					///< "Magic" stack offset indicating the offset is unknown
  };
  FuncCallSpecs(PcodeOp *call_op);					///< Construct based on CALL or CALLIND
  void setAddress(const Address &addr) { entryaddress = addr; }	///< Set (override) the callee's entry address
  PcodeOp *getOp(void) const { return op; }			///< Get the CALL or CALLIND corresponding to \b this
  Funcdata *getFuncdata(void) const { return fd; }		///< Get the Funcdata object associated with the called function
  void setFuncdata(Funcdata *f);				///< Set the Funcdata object associated with the called function
  FuncCallSpecs *clone(PcodeOp *newop) const;			///< Clone \b this given the mirrored p-code CALL
  const string &getName(void) const { return name; }		///< Get the function name associated with the callee
  const Address &getEntryAddress(void) const { return entryaddress; }	///< Get the entry address of the callee
  void setEffectiveExtraPop(int4 epop) { effective_extrapop = epop; }	///< Set the specific \e extrapop associate with \b this call site
  int4 getEffectiveExtraPop(void) const { return effective_extrapop; }	///< Get the specific \e extrapop associate with \b this call site
  uintb getSpacebaseOffset(void) const { return stackoffset; }	///< Get the stack-pointer relative offset at the point of \b this call site
  void setParamshift(int4 val) { paramshift = val; }		///< Set a parameter shift for this call site
  int4 getParamshift(void) const { return paramshift; }		///< Get the parameter shift for this call site
  int4 getMatchCallCount(void) const { return matchCallCount; }	///< Get the number of calls the caller makes to \b this sub-function
  int4 getStackPlaceholderSlot(void) const { return stackPlaceholderSlot; }	///< Get the slot of the stack-pointer placeholder
  void setStackPlaceholderSlot(int4 slot) { stackPlaceholderSlot = slot;
      if (isinputactive) activeinput.setPlaceholderSlot(); }	///< Set the slot of the stack-pointer placeholder
  void clearStackPlaceholderSlot(void) {
    stackPlaceholderSlot = -1; if (isinputactive) activeinput.freePlaceholderSlot(); }	///< Release the stack-pointer placeholder

  void initActiveInput(void);			 ///< Turn on analysis recovering input parameters
  void clearActiveInput(void) { isinputactive = false; }	///< Turn off analysis recovering input parameters
  void initActiveOutput(void) { isoutputactive = true; }	///< Turn on analysis recovering the return value
  void clearActiveOutput(void) { isoutputactive = false; }	///< Turn off analysis recovering the return value
  bool isInputActive(void) const { return isinputactive; }	///< Return \b true if input parameter recovery analysis is active
  bool isOutputActive(void) const { return isoutputactive; }	///< Return \b true if return value recovery analysis is active
  void setBadJumpTable(bool val) { isbadjumptable = val; }	///< Toggle whether \b call site looked like an indirect jump
  bool isBadJumpTable(void) const { return isbadjumptable; }	///< Return \b true if \b this call site looked like an indirect jump
  ParamActive *getActiveInput(void) { return &activeinput; }	///< Get the analysis object for input parameter recovery
  ParamActive *getActiveOutput(void) { return &activeoutput; }	///< Get the analysis object for return value recovery

  bool checkInputJoin(int4 slot1,bool ishislot,Varnode *vn1,Varnode *vn2) const;
  void doInputJoin(int4 slot1,bool ishislot);
  bool lateRestriction(const FuncProto &restrictedProto,vector<Varnode *> &newinput,Varnode *&newoutput);
  void deindirect(Funcdata &data,Funcdata *newfd);
  void forceSet(Funcdata &data,const FuncProto &fp);
  void insertPcode(Funcdata &data);
  void resolveSpacebaseRelative(Funcdata &data,Varnode *phvn);
  void abortSpacebaseRelative(Funcdata &data);
  void finalInputCheck(void);
  void checkInputTrialUse(Funcdata &data,AliasChecker &aliascheck);
  void checkOutputTrialUse(Funcdata &data,vector<Varnode *> &trialvn);
  void buildInputFromTrials(Funcdata &data);
  void buildOutputFromTrials(Funcdata &data,vector<Varnode *> &trialvn);
  int4 getInputBytesConsumed(int4 slot) const;
  bool setInputBytesConsumed(int4 slot,int4 val) const;
  void paramshiftModifyStart(void);
  bool paramshiftModifyStop(Funcdata &data);
  uint4 hasEffectTranslate(const Address &addr,int4 size) const;
  static Varnode *findPreexistingWhole(Varnode *vn1,Varnode *vn2);

  /// \brief Convert FspecSpace addresses to the underlying FuncCallSpecs object
  ///
  /// \param addr is the given \e fspec address
  /// \return the FuncCallSpecs object
  static FuncCallSpecs *getFspecFromConst(const Address &addr) { return (FuncCallSpecs *)(uintp)addr.getOffset(); }

  /// \brief Compare FuncCallSpecs by function entry address
  ///
  /// \param a is the first FuncCallSpecs to compare
  /// \param b is the second to compare
  /// \return \b true if the first should be ordered before the second
  static bool compareByEntryAddress(const FuncCallSpecs *a,const FuncCallSpecs *b) { return a->entryaddress < b->entryaddress; }
  static void countMatchingCalls(const vector<FuncCallSpecs *> &qlst);
};

/// Return the trial associated with the input Varnode to the associated p-code CALL or CALLIND.
/// We take into account the call address parameter (subtract 1) and if the index occurs \e after the
/// index holding the stackpointer placeholder, we subtract an additional 1.
/// \param slot is the input index of the input Varnode
/// \return the corresponding parameter trial
inline const ParamTrial &ParamActive::getTrialForInputVarnode(int4 slot) const

{
  slot -= ((stackplaceholder<0)||(slot<stackplaceholder)) ? 1 : 2;
  return trial[slot];
}

/// \brief Compare two EffectRecords by their start Address
///
/// \param op1 is the first record to compare
/// \param op2 is the other record to compare
/// \return \b true if \b this should be ordered before the other record
inline bool EffectRecord::compareByAddress(const EffectRecord &op1,const EffectRecord &op2)

{
  if (op1.range.space != op2.range.space)
    return (op1.range.space->getIndex() < op2.range.space->getIndex());
  return (op1.range.offset < op2.range.offset);
}

inline bool EffectRecord::operator==(const EffectRecord &op2) const

{
  if (range != op2.range) return false;
  return (type == op2.type);
}

inline bool EffectRecord::operator!=(const EffectRecord &op2) const

{
  if (range != op2.range) return true;
  return (type != op2.type);
}

#endif