forked from cseagle/blc
-
Notifications
You must be signed in to change notification settings - Fork 0
/
coreaction.hh
1061 lines (989 loc) · 49 KB
/
coreaction.hh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/// \file coreaction.hh
/// \brief Core decompilation actions which are indepedent of any particular architecture
///
/// These are the internal actions.
/// They are guaranteed to not to invalidate covers.
/// (if they do they must check the covers themselves)
#ifndef __CORE_ACTION__
#define __CORE_ACTION__
#include "ruleaction.hh"
#include "blockaction.hh"
#include "funcdata.hh"
/// \brief Gather raw p-code for a function.
class ActionStart : public Action {
public:
ActionStart(const string &g) : Action(0,"start",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionStart(getGroup());
}
virtual int4 apply(Funcdata &data) {
data.startProcessing(); return 0; }
};
/// \brief Do any post-processing after decompilation
class ActionStop : public Action {
public:
ActionStop(const string &g) : Action(0,"stop",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionStop(getGroup());
}
virtual int4 apply(Funcdata &data) {
data.stopProcessing(); return 0; }
};
/// \brief Start clean up after main transform phase
class ActionStartCleanUp : public Action {
public:
ActionStartCleanUp(const string &g) : Action(0,"startcleanup",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionStartCleanUp(getGroup());
}
virtual int4 apply(Funcdata &data) {
data.startCleanUp(); return 0; }
};
/// \brief Allow type recovery to start happening
class ActionStartTypes : public Action {
public:
ActionStartTypes(const string &g) : Action(0,"starttypes",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionStartTypes(getGroup());
}
virtual int4 apply(Funcdata &data) {
if (data.startTypeRecovery()) count+=1;
return 0;
}
};
/// \brief Analyze change to the stack pointer across sub-function calls.
class ActionStackPtrFlow : public Action {
AddrSpace *stackspace; ///< Stack space associated with stack-pointer register
bool analysis_finished; ///< True if analysis already performed
static void analyzeExtraPop(Funcdata &data,AddrSpace *stackspace,int4 spcbase);
static bool isStackRelative(Varnode *spcbasein,Varnode *vn,uintb &constval);
static bool adjustLoad(Funcdata &data,PcodeOp *loadop,PcodeOp *storeop);
static int4 repair(Funcdata &data,AddrSpace *id,Varnode *spcbasein,PcodeOp *loadop,uintb constz);
static int4 checkClog(Funcdata &data,AddrSpace *id,int4 spcbase);
public:
ActionStackPtrFlow(const string &g,AddrSpace *ss) : Action(0,"stackptrflow",g) { stackspace = ss; } ///<Constructor
virtual void reset(Funcdata &data) { analysis_finished = false; }
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionStackPtrFlow(getGroup(),stackspace);
}
virtual int4 apply(Funcdata &data);
};
/// \brief Find Varnodes with a vectorized lane scheme and attempt to split the lanes
///
/// The Architecture lists (vector) registers that may be used to perform parallelized operations
/// on \b lanes within the register. This action looks for these registers as Varnodes, determines
/// if a particular lane scheme makes sense in terms of the function's data-flow, and then
/// rewrites the data-flow so that the lanes become explicit Varnodes.
class ActionLaneDivide : public Action {
void collectLaneSizes(Varnode *vn,const LanedRegister &allowedLanes,LanedRegister &checkLanes);
bool processVarnode(Funcdata &data,Varnode *vn,const LanedRegister &lanedRegister,int4 mode);
public:
ActionLaneDivide(const string &g) : Action(rule_onceperfunc,"lanedivide",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionLaneDivide(getGroup());
}
virtual int4 apply(Funcdata &data);
};
/// \brief Make sure pointers into segmented spaces have the correct form.
///
/// Convert user-defined ops defined as segment p-code ops by a cspec tag into the internal CPUI_SEGMENTOP
class ActionSegmentize : public Action {
int4 localcount; ///< Number of times this Action has been performed on the function
public:
ActionSegmentize(const string &g) : Action(0,"segmentize",g) {} ///< Constructor
virtual void reset(Funcdata &data) { localcount = 0; }
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionSegmentize(getGroup());
}
virtual int4 apply(Funcdata &data);
};
/// \brief Apply any overridden forced gotos
class ActionForceGoto : public Action {
public:
ActionForceGoto(const string &g) : Action(0,"forcegoto",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionForceGoto(getGroup());
}
virtual int4 apply(Funcdata &data);
};
// \brief Perform common subexpression elimination
// class ActionCse : public Action {
// public:
// ActionCse(const string &g) : Action(0,"cse",g) {} ///< Constructor
// virtual Action *clone(const ActionGroupList &grouplist) const {
// if (!grouplist.contains(getGroup())) return (Action *)0;
// return new ActionCse(getGroup());
// }
// virtual int4 apply(Funcdata &data);
// };
/// \brief Perform Common Sub-expression Elimination on CPUI_MULTIEQUAL ops
class ActionMultiCse : public Action {
static bool preferredOutput(Varnode *out1,Varnode *out2); ///< Which of two outputs is preferred
static PcodeOp *findMatch(BlockBasic *bl,PcodeOp *target,Varnode *in); ///< Find match to CPUI_MULTIEQUAL
bool processBlock(Funcdata &data,BlockBasic *bl); ///< Search a block for equivalent CPUI_MULTIEQUAL
public:
ActionMultiCse(const string &g) : Action(0,"multicse",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionMultiCse(getGroup());
}
virtual int4 apply(Funcdata &data);
};
/// \brief Check for one CPUI_MULTIEQUAL input set defining more than one Varnode
class ActionShadowVar : public Action {
public:
ActionShadowVar(const string &g) : Action(0,"shadowvar",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionShadowVar(getGroup());
}
virtual int4 apply(Funcdata &data);
};
/// \brief Check for constants, with pointer type, that correspond to global symbols
class ActionConstantPtr : public Action {
int4 localcount; ///< Number of passes made for this function
static SymbolEntry *isPointer(AddrSpace *spc,Varnode *vn,PcodeOp *op,int4 slot,
Address &rampoint,uintb &fullEncoding,Funcdata &data);
public:
ActionConstantPtr(const string &g) : Action(0,"constantptr",g) {} ///< Constructor
virtual void reset(Funcdata &data) { localcount = 0; }
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionConstantPtr(getGroup());
}
virtual int4 apply(Funcdata &data);
};
/// \brief Eliminate locally constant indirect calls
class ActionDeindirect : public Action {
public:
ActionDeindirect(const string &g) : Action(0,"deindirect",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionDeindirect(getGroup());
}
virtual int4 apply(Funcdata &data);
};
/// \brief Transform based on Varnode properties, such as \e read-only and \e volatile
///
/// This performs various transforms that are based on Varnode properties.
/// - Read-only Varnodes are converted to the underlying constant
/// - Volatile Varnodes are converted read/write functions
/// - Varnodes whose values are not consumed are replaced with constant 0 Varnodes
/// - Large Varnodes are flagged for lane analysis
class ActionVarnodeProps : public Action {
void markLanedVarnode(Funcdata &data,Varnode *vn); ///< Mark possible laned register storage
public:
ActionVarnodeProps(const string &g) : Action(0,"varnodeprops",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionVarnodeProps(getGroup());
}
virtual int4 apply(Funcdata &data);
};
/// \brief Mark Varnodes built out of \e legal parameters
///
/// Label a varnode with the \b directwrite attribute if:
/// that varnode can trace at least part of its data-flow ancestry to legal inputs,
/// where \b legal inputs include: globals, spacebase registers, and normal function parameters.
/// The directwrite attribute is set on these inputs initially and then propagated
/// to other varnodes through all other ops except CPUI_INDIRECT. The attribute propagates
/// through CPUI_INDIRECT depending on the setting of -propagateIndirect-.
/// For normal decompilation, propagation through CPUI_INDIRECTs is important for stack and other
/// high-level addrtied variables that need to hold their value over ranges where they are not
/// accessed directly. But propagation adds unnecessary clutter for normalization style analysis.
class ActionDirectWrite : public Action {
bool propagateIndirect; ///< Propagate thru CPUI_INDIRECT ops
public:
ActionDirectWrite(const string &g,bool prop) : Action(0,"directwrite",g) { propagateIndirect=prop; } ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionDirectWrite(getGroup(),propagateIndirect);
}
virtual int4 apply(Funcdata &data);
};
/// \brief Search for input Varnodes that have been officially provided constant values.
///
/// This class injects p-code at the beginning of the function if there is an official \e uponentry
/// injection specified for the prototype model or if there are \e tracked registers for which the
/// user has provided a constant value for.
class ActionConstbase : public Action {
public:
ActionConstbase(const string &g) : Action(0,"constbase",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionConstbase(getGroup());
}
virtual int4 apply(Funcdata &data);
};
/// \brief Mark Varnode objects that hold stack-pointer values and set-up special data-type
class ActionSpacebase : public Action {
public:
ActionSpacebase(const string &g) : Action(0,"spacebase",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionSpacebase(getGroup());
}
virtual int4 apply(Funcdata &data) {
data.spacebase(); return 0; }
};
/// \brief Build Static Single Assignment (SSA) representation for function
class ActionHeritage : public Action {
public:
ActionHeritage(const string &g) : Action(0,"heritage",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionHeritage(getGroup());
}
virtual int4 apply(Funcdata &data) { data.opHeritage(); return 0; }
};
/// \brief Calculate the non-zero mask property on all Varnode objects.
class ActionNonzeroMask : public Action {
public:
ActionNonzeroMask(const string &g) : Action(0,"nonzeromask",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionNonzeroMask(getGroup());
}
virtual int4 apply(Funcdata &data) { data.calcNZMask(); return 0; }
};
/// \brief Fill-in CPUI_CAST p-code ops as required by the casting strategy
///
/// Setting the casts is complicated by type inference and
/// implied variables. By the time this Action is run, the
/// type inference algorithm has labeled every Varnode with what
/// it thinks the type should be. This casting algorithm tries
/// to get the code to legally match this inference result by
/// adding casts. Following the data flow, it tries the best it
/// can to get each token to match the inferred type. For
/// implied variables, the type is completely determined by the
/// syntax of the output language, so implied casts won't work in this case.
/// For most of these cases, the algorithm just changes the type
/// to that dictated by syntax and gets back on track at the
/// next explicit variable in the flow. It tries to avoid losing
/// pointer types however because any CPUI_PTRADD \b mst have a pointer
/// input. In this case, it casts to the necessary pointer type
/// immediately.
class ActionSetCasts : public Action {
static int4 castOutput(PcodeOp *op,Funcdata &data,CastStrategy *castStrategy);
static int4 castInput(PcodeOp *op,int4 slot,Funcdata &data,CastStrategy *castStrategy);
public:
ActionSetCasts(const string &g) : Action(rule_onceperfunc,"setcasts",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionSetCasts(getGroup());
}
virtual int4 apply(Funcdata &data);
};
/// \brief Assign initial high-level HighVariable objects to each Varnode
class ActionAssignHigh : public Action {
public:
ActionAssignHigh(const string &g) : Action(rule_onceperfunc,"assignhigh",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionAssignHigh(getGroup());
}
virtual int4 apply(Funcdata &data) { data.setHighLevel(); return 0; }
};
/// \brief Mark illegal Varnode inputs used only in CPUI_INDIRECT ops
class ActionMarkIndirectOnly : public Action {
public:
ActionMarkIndirectOnly(const string &g) : Action(rule_onceperfunc, "markindirectonly",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionMarkIndirectOnly(getGroup());
}
virtual int4 apply(Funcdata &data) {
data.markIndirectOnly(); return 0; }
};
/// \brief Make \e required Varnode merges as dictated by CPUI_MULTIEQUAL, CPUI_INDIRECT, and \e addrtied property
class ActionMergeRequired : public Action {
public:
ActionMergeRequired(const string &g) : Action(rule_onceperfunc,"mergerequired",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionMergeRequired(getGroup());
}
virtual int4 apply(Funcdata &data) {
data.getMerge().mergeAddrTied(); data.getMerge().mergeMarker(); return 0; }
};
/// \brief Try to merge an op's input Varnode to its output, if they are at the same storage location.
class ActionMergeAdjacent : public Action {
public:
ActionMergeAdjacent(const string &g) : Action(rule_onceperfunc,"mergeadjacent",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionMergeAdjacent(getGroup());
}
virtual int4 apply(Funcdata &data) { data.getMerge().mergeAdjacent(); return 0; }
};
/// \brief Try to merge the input and output Varnodes of a CPUI_COPY op
class ActionMergeCopy : public Action {
public:
ActionMergeCopy(const string &g) : Action(rule_onceperfunc,"mergecopy",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionMergeCopy(getGroup());
}
virtual int4 apply(Funcdata &data) { data.getMerge().mergeOpcode(CPUI_COPY); return 0; }
};
/// \brief Try to merge Varnodes of the same type (if they don't hold different values at the same time)
class ActionMergeType : public Action {
public:
ActionMergeType(const string &g) : Action(rule_onceperfunc,"mergetype",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionMergeType(getGroup());
}
virtual int4 apply(Funcdata &data) {
data.getMerge().mergeByDatatype(data.beginLoc(),data.endLoc()); return 0; }
};
/// \brief Find \b explicit Varnodes: Varnodes that have an explicit token representing them in the output
///
/// In the final output of the syntax tree as source code, all variables are characterized as either
/// - \b explicit, having a specific identifier in the source code, or
/// - \b implied, an intermediate result of an expression with no specific identifier
///
/// This Action does preliminary scanning of Varnodes to determine which should be explicit
/// in the final output. Basically, if there is symbol information associated, the possibility
/// of aliasing, or if there are too many reads of a Varnode, it should be considered explicit.
class ActionMarkExplicit : public Action {
/// This class holds a single entry in a stack used to traverse Varnode expressions
struct OpStackElement {
Varnode *vn; ///< The Varnode at this particular point in the path
int4 slot; ///< The slot of the first input Varnode to traverse in this subexpression
int4 slotback; ///< The slot(+1) of the last input Varnode to traverse in this subexpression
OpStackElement(Varnode *v); ///< Constructor
};
static int4 baseExplicit(Varnode *vn,int4 maxref); ///< Make initial determination if a Varnode should be \e explicit
static int4 multipleInteraction(vector<Varnode *> &multlist); ///< Find multiple descendant chains
static void processMultiplier(Varnode *vn,int4 max); ///< For a given multi-descendant Varnode, decide if it should be explicit
static void checkNewToConstructor(Funcdata &data,Varnode *vn); ///< Set special properties on output of CPUI_NEW
public:
ActionMarkExplicit(const string &g) : Action(rule_onceperfunc,"markexplicit",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionMarkExplicit(getGroup());
}
virtual int4 apply(Funcdata &data);
};
/// \brief Mark all the \e implied Varnode objects, which will have no explicit token in the output
class ActionMarkImplied : public Action {
/// This class holds a single entry in a stack used to forward traverse Varnode expressions
struct DescTreeElement {
Varnode *vn; ///< The Varnode at this particular point in the path
list<PcodeOp *>::const_iterator desciter; ///< The current edge being traversed
DescTreeElement(Varnode *v) {
vn = v; desciter = v->beginDescend(); } ///< Constructor
};
static bool isPossibleAliasStep(Varnode *vn1,Varnode *vn2); ///< Check for additive relationship
static bool isPossibleAlias(Varnode *vn1,Varnode *vn2,int4 depth); ///< Check for possible duplicate value
static bool checkImpliedCover(Funcdata &data,Varnode *vn); ///< Check for cover violation if Varnode is implied
public:
ActionMarkImplied(const string &g) : Action(rule_onceperfunc,"markimplied",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionMarkImplied(getGroup());
}
virtual int4 apply(Funcdata &data);
};
/// \brief Choose names for all high-level variables (HighVariables)
class ActionNameVars : public Action {
/// This class is a record in a database used to store and lookup potential names
struct OpRecommend {
Datatype *ct; ///< The data-type associated with a name
string namerec; ///< A possible name for a variable
};
static void makeRec(ProtoParameter *param,Varnode *vn,map<HighVariable *,OpRecommend> &recmap);
static void lookForBadJumpTables(Funcdata &data); ///< Mark the switch variable for bad jump-tables
static void lookForRecommendedNames(Funcdata &data); ///< Try to apply names from unlocked symbols
static void lookForFuncParamNames(Funcdata &data,const vector<Varnode *> &varlist);
public:
ActionNameVars(const string &g) : Action(rule_onceperfunc,"namevars",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionNameVars(getGroup());
}
virtual int4 apply(Funcdata &data);
};
/// \brief Remove unreachable blocks
class ActionUnreachable : public Action {
public:
ActionUnreachable(const string &g) : Action(0,"unreachable",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionUnreachable(getGroup());
}
virtual int4 apply(Funcdata &data);
};
/// \brief Remove blocks that do nothing
class ActionDoNothing : public Action {
public:
ActionDoNothing(const string &g) : Action(rule_repeatapply,"donothing",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionDoNothing(getGroup());
}
virtual int4 apply(Funcdata &data);
};
/// \brief Get rid of \b redundant branches: duplicate edges between the same input and output block
class ActionRedundBranch : public Action {
public:
ActionRedundBranch(const string &g) : Action(0,"redundbranch",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionRedundBranch(getGroup());
}
virtual int4 apply(Funcdata &data);
};
/// \brief Remove conditional branches if the condition is constant
class ActionDeterminedBranch : public Action {
public:
ActionDeterminedBranch(const string &g) : Action(0,"determinedbranch",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionDeterminedBranch(getGroup());
}
virtual int4 apply(Funcdata &data);
};
/// \brief Dead code removal. Eliminate \e dead p-code ops
///
/// This is a very fine grained algorithm, it detects usage
/// of individual bits within the Varnode, not just use of the
/// Varnode itself. Each Varnode has a \e consumed word, which
/// indicates if a bit in the Varnode is being used, and it has
/// two flags layed out as follows:
/// - Varnode::lisconsume = varnode is in the working list
/// - Varnode::vacconsume = vacuously used bit
/// there is a path from the varnode through assignment
/// op outputs down to a varnode that is used
///
/// The algorithm works by back propagating the \e consumed value
/// up from the output of the op to its inputs, starting with
/// a set of seed Varnodes which are marked as completely used
/// (function inputs, branch conditions, ...) For each propagation
/// the particular op being passed through can transform the
/// "bit usage" vector of the output to obtain the input.
class ActionDeadCode : public Action {
static void pushConsumed(uintb val,Varnode *vn,vector<Varnode *> &worklist);
static void propagateConsumed(vector<Varnode *> &worklist);
static bool neverConsumed(Varnode *vn,Funcdata &data);
public:
ActionDeadCode(const string &g) : Action(0,"deadcode",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionDeadCode(getGroup());
}
virtual int4 apply(Funcdata &data);
};
/// \brief Propagate conditional constants
class ActionConditionalConst : public Action {
public:
ActionConditionalConst(const string &g) : Action(0,"condconst",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionConditionalConst(getGroup());
}
virtual int4 apply(Funcdata &data);
void propagateConstant(Varnode *varVn,Varnode *constVn,FlowBlock *constBlock,Funcdata &data);
};
/// \brief Normalize jump-table construction.
///
/// This involves folding switch variable normalization and the \b guard instructions into
/// the \b switch action. The case labels are also calculated based on the normalization.
class ActionSwitchNorm : public Action {
public:
ActionSwitchNorm(const string &g) : Action(0,"switchnorm",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionSwitchNorm(getGroup());
}
virtual int4 apply(Funcdata &data);
};
/// \brief Prepare function prototypes for "normalize" simplification.
///
/// The "normalize" simplification style has the fundamental requirement that the input parameter
/// types must not be locked, as locking can cause changes in the data-flow that "normalize" is
/// trying to normalize, because:
/// 1) The decompiler views locking as useful aliasing information
/// 2) Locking forces varnodes to exist up-front, which can affect subflow analysis
/// 3) ... probably other differences
///
/// This action removes any input symbols on the function, locked or otherwise,
/// Similarly there should be no lock on the output and no lock on the prototype model
class ActionNormalizeSetup : public Action {
public:
ActionNormalizeSetup(const string &g) : Action(rule_onceperfunc,"normalizesetup",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionNormalizeSetup(getGroup());
}
virtual int4 apply(Funcdata &data);
};
/// \brief Lay down locked input and output data-type information.
///
/// Build forced input/output Varnodes and extend them as appropriate.
/// Set types on output forced Varnodes (input types are set automatically by the database).
/// Initialize output recovery process.
class ActionPrototypeTypes: public Action {
public:
void extendInput(Funcdata &data,Varnode *invn,ProtoParameter *param,BlockBasic *topbl);
ActionPrototypeTypes(const string &g) : Action(rule_onceperfunc,"prototypetypes",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionPrototypeTypes(getGroup());
}
virtual int4 apply(Funcdata &data);
};
/// \brief Find a prototype for each sub-function
///
/// This loads prototype information, if it exists for each sub-function. If no explicit
/// prototype exists, a default is selected. If the prototype model specifies
/// \e uponreturn injection, the p-code is injected at this time.
class ActionDefaultParams : public Action {
public:
ActionDefaultParams(const string &g) : Action(rule_onceperfunc,"defaultparams",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionDefaultParams(getGroup());
}
virtual int4 apply(Funcdata &data);
};
/// \brief Define formal link between stack-pointer values before and after sub-function calls.
///
/// Change to the stack-pointer across a sub-function is called \b extrapop. This class
/// makes sure there is p-code relationship between the Varnode coming into a sub-function
/// and the Varnode coming out. If the \e extrapop is known, the p-code will be
/// a CPUI_COPY or CPUI_ADD. If it is unknown, a CPUI_INDIRECT will be inserted that gets
/// filled in by ActionStackPtrFlow.
class ActionExtraPopSetup : public Action {
AddrSpace *stackspace; ///< The stack space to analyze
public:
ActionExtraPopSetup(const string &g,AddrSpace *ss) : Action(rule_onceperfunc,"extrapopsetup",g) { stackspace = ss; } ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionExtraPopSetup(getGroup(),stackspace);
}
virtual int4 apply(Funcdata &data);
};
/// \brief Prepare for data-flow analysis of function parameters
///
/// If exact prototypes are known for sub-functions, insert the appropriate
/// Varnodes to match the parameters. If not known, prepare the sub-function for
/// the parameter recovery process.
class ActionFuncLink : public Action {
friend class ActionFuncLinkOutOnly;
static void funcLinkInput(FuncCallSpecs *fc,Funcdata &data);
static void funcLinkOutput(FuncCallSpecs *fc,Funcdata &data);
public:
ActionFuncLink(const string &g) : Action(rule_onceperfunc,"funclink",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionFuncLink(getGroup());
}
virtual int4 apply(Funcdata &data);
};
/// \brief Prepare for data-flow analysis of function parameters, when recovery isn't required.
///
/// If the "protorecovery" action group is not enabled, this
/// Action probably should be. It sets up only the potential
/// sub-function outputs (not the inputs) otherwise local uses of
/// the output registers may be incorrectly heritaged, screwing
/// up the local analysis (i.e. for jump-tables) even though we
/// don't care about the function inputs.
class ActionFuncLinkOutOnly : public Action {
public:
ActionFuncLinkOutOnly(const string &g) : Action(rule_onceperfunc,"funclink_outonly",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionFuncLinkOutOnly(getGroup());
}
virtual int4 apply(Funcdata &data);
};
/// \brief Deal with situations that look like double precision parameters
///
/// Check each sub-function for parameter concatenation situations:
/// - if the sub-function is in the middle of parameter recovery, check if the CONCAT
/// is an artifact of the heritage process and arbitrarily grouping parameters together.
/// - if the CONCAT is correct, producing a locked double precision parameter, make
/// sure the pieces are properly labeled.
class ActionParamDouble : public Action {
public:
ActionParamDouble(const string &g) : Action(0, "paramdouble",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionParamDouble(getGroup());
}
virtual int4 apply(Funcdata &data);
};
/// \brief Determine active parameters to sub-functions
///
/// This is the final stage of the parameter recovery process, when
/// a prototype for a sub-function is not explicitly known. Putative input Varnode
/// parameters are collected by the Heritage process. This class determines
/// which of these Varnodes are being used as parameters.
/// This needs to be called \b after ActionHeritage and \b after ActionDirectWrite
/// but \b before any simplification or copy propagation has been performed.
class ActionActiveParam : public Action {
public:
ActionActiveParam(const string &g) : Action( 0, "activeparam",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionActiveParam(getGroup());
}
virtual int4 apply(Funcdata &data);
};
/// \brief Determine which sub-functions have active output Varnodes
///
/// This is analogous to ActionActiveParam but for sub-function return values.
class ActionActiveReturn : public Action {
public:
ActionActiveReturn(const string &g) : Action( 0, "activereturn",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionActiveReturn(getGroup());
}
virtual int4 apply(Funcdata &data);
};
// \brief If there are any sub-function calls with \e paramshifts, add the shifted parameters.
// class ActionParamShiftStart : public Action {
// public:
// ActionParamShiftStart(const string &g) : Action( rule_onceperfunc, "paramshiftstart",g) {} ///< Constructor
// virtual Action *clone(const ActionGroupList &grouplist) const {
// if (!grouplist.contains(getGroup())) return (Action *)0;
// return new ActionParamShiftStart(getGroup());
// }
// virtual int4 apply(Funcdata &data);
// };
// \brief If there are any sub-function calls with \e paramshifts, remove the shifted parameters.
// class ActionParamShiftStop : public Action {
// bool paramshiftsleft;
// public:
// ActionParamShiftStop(const string &g) : Action( 0, "paramshiftstop",g) {} ///< Constructor
// virtual void reset(Funcdata &data) { paramshiftsleft = true; }
// virtual Action *clone(const ActionGroupList &grouplist) const {
// if (!grouplist.contains(getGroup())) return (Action *)0;
// return new ActionParamShiftStop(getGroup());
// }
// virtual int4 apply(Funcdata &data);
// };
/// \brief Determine data-flow holding the \e return \e value of the function.
class ActionReturnRecovery : public Action {
static void buildReturnOutput(ParamActive *active,PcodeOp *retop,Funcdata &data);
public:
ActionReturnRecovery(const string &g) : Action( 0, "returnrecovery",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionReturnRecovery(getGroup());
}
virtual int4 apply(Funcdata &data);
};
/// \brief Restrict possible range of local variables
///
/// Mark what we know of parameters and unaffected stores
/// so that they cannot be treated as local variables.
class ActionRestrictLocal : public Action {
public:
ActionRestrictLocal(const string &g) : Action(0,"restrictlocal",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionRestrictLocal(getGroup());
}
virtual int4 apply(Funcdata &data);
};
/// \brief Get rid of registers with trash values.
///
/// Register locations called \b likely \b trash are read as a side-effect of some instruction
/// the compiler was using. The canonical example in x86 code is the
/// PUSH ECX
/// which compilers use to create space on the stack without caring about what's in ECX.
/// Even though the decompiler can see that the read ECX value is never getting used directly
/// by the function, because the value is getting copied to the stack, the decompiler frequently
/// can't tell if the value has been aliased across sub-function calls. By marking the ECX register
/// as \b likely \ trash the decompiler will assume that, unless there is a direct read of the
/// incoming ECX, none of subfunctions alias the stack location where ECX was stored. This
/// allows the spurious references to the register to be removed.
class ActionLikelyTrash : public Action {
static uint4 countMarks(PcodeOp *op);
static bool traceTrash(Varnode *vn,vector<PcodeOp *> &indlist);
public:
ActionLikelyTrash(const string &g) : Action(0,"likelytrash",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionLikelyTrash(getGroup());
}
virtual int4 apply(Funcdata &data);
};
/// \brief Create symbols that map out the local stack-frame for the function.
///
/// This produces on intermediate view of symbols on the stack.
class ActionRestructureVarnode : public Action {
int4 numpass; ///< Number of passes performed for this function
public:
ActionRestructureVarnode(const string &g) : Action(0,"restructure_varnode",g) {} ///< Constructor
virtual void reset(Funcdata &data) { numpass = 0; }
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionRestructureVarnode(getGroup());
}
virtual int4 apply(Funcdata &data);
};
/// \brief Create symbols that map out the local stack-frame for the function.
///
/// This produces the final set of symbols on the stack.
class ActionRestructureHigh : public Action {
public:
ActionRestructureHigh(const string &g) : Action(0,"restructure_high",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionRestructureHigh(getGroup());
}
virtual int4 apply(Funcdata &data);
};
/// \brief Create symbols for any discovered global variables in the function.
class ActionMapGlobals : public Action {
public:
ActionMapGlobals(const string &g) : Action(rule_onceperfunc,"mapglobals",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionMapGlobals(getGroup());
}
virtual int4 apply(Funcdata &data) { data.mapGlobals(); return 0; }
};
/// \brief Calculate the prototype for the function.
///
/// If the prototype wasn't originally known, the discovered input Varnodes are analyzed
/// to determine a prototype based on the prototype model.
class ActionInputPrototype : public Action {
public:
ActionInputPrototype(const string &g) : Action(rule_onceperfunc,"inputprototype",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionInputPrototype(getGroup());
}
virtual int4 apply(Funcdata &data);
};
/// \brief Set the (already) recovered output data-type as a formal part of the prototype
class ActionOutputPrototype : public Action {
public:
ActionOutputPrototype(const string &g) : Action(rule_onceperfunc,"outputprototype",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionOutputPrototype(getGroup());
}
virtual int4 apply(Funcdata &data);
};
/// \brief Adjust improperly justified parameters
///
/// Scan through all inputs, find Varnodes that look like improperly justified input parameters
/// create a new full input, and change the old partial input to be formed as a CPUI_SUBPIECE of the
/// full input
class ActionUnjustifiedParams : public Action {
public:
ActionUnjustifiedParams(const string &g) : Action(0,"unjustparams",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionUnjustifiedParams(getGroup());
}
virtual int4 apply(Funcdata &data);
};
/// \brief Infer and propagate data-types.
///
/// Atomic data-types are ordered from \e most specified to \e least specified.
/// This is extended rescursively to an ordering on composite data-types via Datatype::typeOrder().
/// A local data-type is calculated for each Varnode by looking at the data-types
/// expected by the PcodeOps it is directly involved in (as input or output).
/// Every Varnode has 1 chance to propagate its information throughout the graph
/// along COPY,LOAD,STORE,ADD,MULTIEQUAL,and INDIRECT edges. The propagation is
/// done with a depth first search along propagating edges. If the propagated
/// data-type is the same, less than, or if the varnode had been propagated through
/// already, that branch is trimmed. Every edge can theoretically get traversed
/// once, i.e. the search allows the type to propagate through a looping edge,
/// but immediately truncates.
/// This is probably quadratic in the worst case, if each Varnode has a higher
/// type and propagates it to the entire graph. But it is linear in practice,
/// because there are generally only two or three levels of type, so only one
/// or two Varnodes are likely to propagate widely within a component, and
/// the others get truncated immediately. An initial sort on the data-type level
/// of the Varnodes, so that the highest-level types are propagated first,
/// would probably fix the worst-case, but this seems unnecessary.
/// Complications:
/// TYPE_SPACEBASE is a problem because we have to make sure that it doesn't
/// propagate.
/// Also, offsets off of pointers to TYPE_SPACEBASE look up the data-type in the
/// local map. Then ActionRestructure uses data-type information recovered by
/// this algorithm to reconstruct the local map. This causes a feedback loop
/// which allows type information recovered about mapped Varnodes to be propagated
/// to pointer Varnodes which point to the mapped object. Unfortunately under
/// rare circumstances, this feedback-loop does not converge for some reason.
/// Rather than hunt this down, I've put an arbitrary iteration limit on
/// the data-type propagation algorithm, which reports a warning if the limit is
/// reached and then aborts additional propagation so that decompiling can terminate.
class ActionInferTypes : public Action {
#ifdef TYPEPROP_DEBUG
static void propagationDebug(Architecture *glb,Varnode *vn,const Datatype *newtype,PcodeOp *op,int4 slot,Varnode *ptralias);
#endif
int4 localcount; ///< Number of passes performed for this function
static void buildLocaltypes(Funcdata &data); ///< Assign initial data-type based on local info
static bool writeBack(Funcdata &data); ///< Commit the final propagated data-types to Varnodes
static int4 propagateAddPointer(PcodeOp *op,int4 slot); ///< Test if edge is pointer plus a constant
static Datatype *propagateAddIn2Out(TypeFactory *typegrp,PcodeOp *op,int4 inslot);
static bool propagateGoodEdge(PcodeOp *op,int4 inslot,int4 outslot,Varnode *invn);
static bool propagateTypeEdge(TypeFactory *typegrp,PcodeOp *op,int4 inslot,int4 outslot);
static void propagateOneType(TypeFactory *typegrp,Varnode *vn);
static void propagateRef(Funcdata &data,Varnode *vn,const Address &addr);
static void propagateSpacebaseRef(Funcdata &data,Varnode *spcvn);
public:
ActionInferTypes(const string &g) : Action(0,"infertypes",g) {} ///< Constructor
virtual void reset(Funcdata &data) { localcount = 0; }
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionInferTypes(getGroup());
}
virtual int4 apply(Funcdata &data);
};
/// \brief Locate \e shadow Varnodes and adjust them so they are hidden
///
/// A \b shadow Varnode is an internal copy of another Varnode that a compiler
/// produces but that really isn't a separate variable. In practice, a Varnode
/// and its shadow get grouped into the same HighVariable, then without this
/// Action the decompiler output shows duplicate COPY statements. This Action
/// alters the defining op of the shadow so that the duplicate statement doesn't print.
class ActionHideShadow : public Action {
public:
ActionHideShadow(const string &g) : Action(rule_onceperfunc,"hideshadow",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionHideShadow(getGroup());
}
virtual int4 apply(Funcdata &data);
};
/// \brief Replace COPYs from the same source with a single dominant COPY
class ActionDominantCopy : public Action {
public:
ActionDominantCopy(const string &g) : Action(rule_onceperfunc,"dominantcopy",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionDominantCopy(getGroup());
}
virtual int4 apply(Funcdata &data) { data.getMerge().processCopyTrims(); return 0; }
};
/// \brief Mark COPY operations between Varnodes representing the object as \e non-printing
class ActionCopyMarker : public Action {
public:
ActionCopyMarker(const string &g) : Action(rule_onceperfunc,"copymarker",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionCopyMarker(getGroup());
}
virtual int4 apply(Funcdata &data) { data.getMerge().markInternalCopies(); return 0; }
};
/// \brief Attach \e dynamically mapped symbols to Varnodes in time for data-type propagation
class ActionDynamicMapping : public Action {
public:
ActionDynamicMapping(const string &g) : Action(0,"dynamicmapping",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionDynamicMapping(getGroup());
}
virtual int4 apply(Funcdata &data);
};
/// \brief Make final attachments of \e dynamically mapped symbols to Varnodes
class ActionDynamicSymbols : public Action {
public:
ActionDynamicSymbols(const string &g) : Action(rule_onceperfunc,"dynamicsymbols",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionDynamicSymbols(getGroup());
}
virtual int4 apply(Funcdata &data);
};
/// \brief Add warnings for prototypes that aren't modeled properly
class ActionPrototypeWarnings : public Action {
public:
ActionPrototypeWarnings(const string &g) : Action(rule_onceperfunc,"prototypewarnings",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Action *)0;
return new ActionPrototypeWarnings(getGroup());
}
virtual int4 apply(Funcdata &data);
};
extern void universal_action(Architecture *conf); ///< The generic decompilation action