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
/* ###
 * IP: GHIDRA
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "options.hh"
#include "funcdata.hh"
#include "flow.hh"
#include "printc.hh"

/// If the parameter is "on" return \b true, if "off" return \b false.
/// Any other value causes an exception.
/// \param p is the parameter
/// \return the parsed boolean value
bool ArchOption::onOrOff(const string &p)

{
  if (p.size()==0)
    return true;
  if (p == "on")
    return true;
  if (p == "off")
    return false;
  throw ParseError("Must specify toggle value, on/off");
}

/// To facilitate command parsing, enter the new ArchOption instance into
/// the map based on its name
/// \param option is the new ArchOption instance
void OptionDatabase::registerOption(ArchOption *option)

{
  optionmap[option->getName()] = option;
}

/// Register all possible ArchOption objects with this database and set-up the parsing map.
/// \param g is the Architecture owning \b this database
OptionDatabase::OptionDatabase(Architecture *g)

{
  glb = g;
  registerOption(new OptionExtraPop());
  registerOption(new OptionReadOnly());
  registerOption(new OptionIgnoreUnimplemented());
  registerOption(new OptionErrorUnimplemented());
  registerOption(new OptionErrorReinterpreted());
  registerOption(new OptionErrorTooManyInstructions());
  registerOption(new OptionDefaultPrototype());
  registerOption(new OptionInferConstPtr());
  registerOption(new OptionForLoops());
  registerOption(new OptionInline());
  registerOption(new OptionNoReturn());
  registerOption(new OptionStructAlign());
  registerOption(new OptionProtoEval());
  registerOption(new OptionWarning());
  registerOption(new OptionNullPrinting());
  registerOption(new OptionInPlaceOps());
  registerOption(new OptionConventionPrinting());
  registerOption(new OptionNoCastPrinting());
  registerOption(new OptionMaxLineWidth());
  registerOption(new OptionIndentIncrement());
  registerOption(new OptionCommentIndent());
  registerOption(new OptionCommentStyle());
  registerOption(new OptionCommentHeader());
  registerOption(new OptionCommentInstruction());
  registerOption(new OptionIntegerFormat());
  registerOption(new OptionCurrentAction());
  registerOption(new OptionAllowContextSet());
  registerOption(new OptionSetAction());
  registerOption(new OptionSetLanguage());
  registerOption(new OptionJumpLoad());
  registerOption(new OptionToggleRule());
  registerOption(new OptionAliasBlock());
  registerOption(new OptionMaxInstruction());
  registerOption(new OptionNamespaceStrategy());
}

OptionDatabase::~OptionDatabase(void)

{
  map<string,ArchOption *>::iterator iter;
  for(iter=optionmap.begin();iter!=optionmap.end();++iter)
    delete (*iter).second;
}

/// Perform an \e option \e command directly, given its name and optional parameters
/// \param nm is the registered name of the option
/// \param p1 is the first optional parameter
/// \param p2 is the second optional parameter
/// \param p3 is the third optional parameter
/// \return the confirmation/failure method after trying to apply the option
string OptionDatabase::set(const string &nm,const string &p1,const string &p2,const string &p3)

{
  map<string,ArchOption *>::const_iterator iter;
  iter = optionmap.find(nm);
  if (iter == optionmap.end())
    throw ParseError("Unknown option: "+nm);
  ArchOption *opt = (*iter).second;
  return opt->apply(glb,p1,p2,p3);
}

/// Unwrap the name and optional parameters and call method set()
/// \param el is the command XML tag
void OptionDatabase::parseOne(const Element *el)

{
  const string &optname( el->getName() );
  const List &list(el->getChildren());
  List::const_iterator iter;
  
  string p1,p2,p3;

  iter = list.begin();
  if (iter != list.end()) {
    p1 = (*iter)->getContent();
    ++iter;
    if (iter != list.end()) {
      p2 = (*iter)->getContent();
      ++iter;
      if (iter != list.end()) {
	p3 = (*iter)->getContent();
	++iter;
	if (iter != list.end())
	  throw LowlevelError("Too many parameters to option: "+optname);
      }
    }
  }
  else
    p1 = el->getContent();	// If no children, content is param 1
  set(optname,p1,p2,p3);
}

/// Parse the \<optionslist> tag, treating each sub-tag as an \e option \e command.
/// \param el is the \<optionslist> tag
void OptionDatabase::restoreXml(const Element *el)

{
  const List &list(el->getChildren());
  List::const_iterator iter;

  for(iter=list.begin();iter!=list.end();++iter)
    parseOne(*iter);
}

/// \class OptionExtraPop
/// \brief Set the \b extrapop parameter used by the (default) prototype model.
///
/// The \b extrapop for a function is the number of bytes popped from the stack that
/// a calling function can assume when this function is called.
///
/// The first parameter is the integer value to use as the \e extrapop, or the special
/// value "unknown" which triggers the \e extrapop recovery analysis.
///
/// The second parameter, if present, indicates a specific function to modify. Otherwise,
/// the default prototype model is modified.
string OptionExtraPop::apply(Architecture *glb,const string &p1,const string &p2,const string &p3) const

{
  int4 expop = -300;
  string res;
  if (p1 == "unknown")
    expop = ProtoModel::extrapop_unknown;
  else {
    istringstream s1(p1);
    s1.unsetf(ios::dec | ios::hex | ios::oct); // Let user specify base
    s1 >> expop;
  }
  if (expop == -300)
    throw ParseError("Bad extrapop adjustment parameter");
  if (p2.size() != 0) {
    Funcdata *fd;
    fd = glb->symboltab->getGlobalScope()->queryFunction( p2 );
    if (fd == (Funcdata *)0)
      throw RecovError("Unknown function name: "+p2);
    fd->getFuncProto().setExtraPop(expop);
    res = "ExtraPop set for function "+p2;
  }
  else {
    glb->defaultfp->setExtraPop(expop);
    if (glb->evalfp_current != (ProtoModel *)0)
      glb->evalfp_current->setExtraPop(expop);
    if (glb->evalfp_called != (ProtoModel *)0)
      glb->evalfp_called->setExtraPop(expop);
    res = "Global extrapop set";
  }
  return res;
}

/// \class OptionReadOnly
/// \brief Toggle whether read-only memory locations have their value propagated
///
/// Setting this to "on", causes the decompiler to treat read-only memory locations as
/// constants that can be propagated.
string OptionReadOnly::apply(Architecture *glb,const string &p1,const string &p2,const string &p3) const

{
  if (p1.size()==0)
    throw ParseError("Read-only option must be set \"on\" or \"off\"");
  glb->readonlypropagate = onOrOff(p1);
  if (glb->readonlypropagate)
    return "Read-only memory locations now propagate as constants";
  return "Read-only memory locations now do not propagate";
}

/// \class OptionDefaultPrototype
/// \brief Set the default prototype model for analyzing unknown functions
///
/// The first parameter must give the name of a registered prototype model.
string OptionDefaultPrototype::apply(Architecture *glb,const string &p1,const string &p2,const string &p3) const

{
  glb->setDefaultModel(p1);
  return "Set default prototype to "+p1;
}

/// \class OptionInferConstPtr
/// \brief Toggle whether the decompiler attempts to infer constant pointers
///
/// Setting the first parameter to "on" causes the decompiler to check if unknown
/// constants look like a reference to a known symbol's location.
string OptionInferConstPtr::apply(Architecture *glb,const string &p1,const string &p2,const string &p3) const

{
  bool val = onOrOff(p1);

  string res;
  if (val) {
    res = "Constant pointers are now inferred";
    glb->infer_pointers = true;
  }
  else {
    res = "Constant pointers must now be set explicitly";
    glb->infer_pointers = false;
  }
  return res;
}

/// \class OptionForLoops
/// \brief Toggle whether the decompiler attempts to recover \e for-loop variables
///
/// Setting the first parameter to "on" causes the decompiler to search for a suitable loop variable
/// controlling iteration of a \e while-do block.  The \e for-loop displays the following on a single line:
///    - loop variable initializer (optional)
///    - loop condition
///    - loop variable incrementer
///
string OptionForLoops::apply(Architecture *glb,const string &p1,const string &p2,const string &p3) const

{
  glb->analyze_for_loops = onOrOff(p1);

  string res = "Recovery of for-loops is " + p1;
  return res;
}

/// \class OptionInline
/// \brief Mark/unmark a specific function as \e inline
///
/// The first parameter gives the symbol name of a function. The second parameter is
/// true" to set the \e inline property, "false" to clear.
string OptionInline::apply(Architecture *glb,const string &p1,const string &p2,const string &p3) const

{
  Funcdata *infd = glb->symboltab->getGlobalScope()->queryFunction( p1 );
  if (infd == (Funcdata *)0)
    throw RecovError("Unknown function name: "+p1);
  bool val;
  if (p2.size()==0)
    val = true;
  else
    val = (p2 == "true");
  infd->getFuncProto().setInline(val);
  string prop;
  if (val)
    prop = "true";
  else
    prop = "false";
  string res = "Inline property for function "+p1+" = "+prop;
  return res;
}

/// \class OptionNoReturn
/// \brief Mark/unmark a specific function with the \e noreturn property
///
/// The first parameter is the symbol name of the function. The second parameter
/// is "true" to enable the \e noreturn property, "false" to disable.
string OptionNoReturn::apply(Architecture *glb,const string &p1,const string &p2,const string &p3) const

{
  Funcdata *infd = glb->symboltab->getGlobalScope()->queryFunction( p1 );
  if (infd == (Funcdata *)0)
    throw RecovError("Unknown function name: "+p1);
  bool val;
  if (p2.size()==0)
    val = true;
  else
    val = (p2 == "true");
  infd->getFuncProto().setNoReturn(val);
  string prop;
  if (val)
    prop = "true";
  else
    prop = "false";
  string res = "No return property for function "+p1+" = "+prop;
  return res;
}

/// \class OptionStructAlign
/// \brief Alter the "structure alignment" data organization setting
///
/// The first parameter must an integer value indicating the desired alignment
string OptionStructAlign::apply(Architecture *glb,const string &p1,const string &p2,const string &p3) const

{
  int4 val  = -1;
  istringstream s(p1);
  s >> dec >> val;
  if (val == -1)
    throw ParseError("Missing alignment value");

  glb->types->setStructAlign(val);
  return "Structure alignment set";
}

/// \class OptionWarning
/// \brief Toggle whether a warning should be issued if a specific action/rule is applied.
///
/// The first parameter gives the name of the Action or RuleAction.  The second parameter
/// is "on" to turn on warnings, "off" to turn them off.
string OptionWarning::apply(Architecture *glb,const string &p1,const string &p2,const string &p3) const

{
  if (p1.size()==0)
    throw ParseError("No action/rule specified");
  bool val;
  if (p2.size()==0)
    val = true;
  else
    val = onOrOff(p2);
  bool res = glb->allacts.getCurrent()->setWarning(val,p1);
  if (!res)
    throw RecovError("Bad action/rule specifier: "+p1);
  string prop;
  prop = val ? "on" : "off";
  return "Warnings for "+p1+" turned "+prop;
}

/// \class OptionNullPrinting
/// \brief Toggle whether null pointers should be printed as the string "NULL"
string OptionNullPrinting::apply(Architecture *glb,const string &p1,const string &p2,const string &p3) const

{
  bool val = onOrOff(p1);
  if (glb->print->getName() != "c-language")
    return "Only c-language accepts the null printing option";
  PrintC *lng = (PrintC *)glb->print;
  lng->setNULLPrinting(val);
  string prop;
  prop = val ? "on" : "off";
  return "Null printing turned "+prop;
}

/// \class OptionInPlaceOps
/// \brief Toggle whether \e in-place operators (+=, *=, &=, etc.) are emitted by the decompiler
string OptionInPlaceOps::apply(Architecture *glb,const string &p1,const string &p2,const string &p3) const

{
  bool val = onOrOff(p1);
  if (glb->print->getName() != "c-language")
    return "Can only set inplace operators for C language";
  PrintC *lng = (PrintC *)glb->print;
  lng->setInplaceOps(val);
  string prop;
  prop = val ? "on" : "off";
  return "Inplace operators turned "+prop;
}

/// \class OptionConventionPrinting
/// \brief Toggle whether the \e calling \e convention is printed when emitting function prototypes
string OptionConventionPrinting::apply(Architecture *glb,const string &p1,const string &p2,const string &p3) const

{
  bool val = onOrOff(p1);
  if (glb->print->getName() != "c-language")
    return "Can only set convention printing for C language";
  PrintC *lng = (PrintC *)glb->print;
  lng->setConvention(val);
  string prop;
  prop = val ? "on" : "off";
  return "Convention printing turned "+prop;
}

/// \class OptionNoCastPrinting
/// \brief Toggle whether \e cast syntax is emitted by the decompiler or stripped
string OptionNoCastPrinting::apply(Architecture *glb,const string &p1,const string &p2,const string &p3) const

{
  bool val = onOrOff(p1);
  PrintC *lng = dynamic_cast<PrintC *>(glb->print);
  if (lng == (PrintC *)0)
    return "Can only set no cast printing for C language";
  lng->setNoCastPrinting(val);
  string prop;
  prop = val ? "on" : "off";
  return "No cast printing turned "+prop;
}

/// \class OptionHideExtensions
/// \brief Toggle whether implied extensions (ZEXT or SEXT) are printed
string OptionHideExtensions::apply(Architecture *glb,const string &p1,const string &p2,const string &p3) const

{
  bool val = onOrOff(p1);
  PrintC *lng = dynamic_cast<PrintC *>(glb->print);
  if (lng == (PrintC *)0)
    return "Can only toggle extension hiding for C language";
  lng->setHideImpliedExts(val);
  string prop;
  prop = val ? "on" : "off";
  return "Implied extension hiding turned "+prop;
}

/// \class OptionMaxLineWidth
/// \brief Set the maximum number of characters per decompiled line
///
/// The first parameter is an integer value passed to the pretty printer as the maximum
/// number of characters to emit in a single line before wrapping.
string OptionMaxLineWidth::apply(Architecture *glb,const string &p1,const string &p2,const string &p3) const

{
  istringstream s(p1);
  s.unsetf(ios::dec | ios::hex | ios::oct);
  int4 val = -1;
  s >> val;
  if (val==-1)
    throw ParseError("Must specify integer linewidth");
  glb->print->setMaxLineSize(val);
  return "Maximum line width set to "+p1;
}

/// \class OptionIndentIncrement
/// \brief Set the number of characters to indent per nested scope.
///
/// The first parameter is the integer value specifying how many characters to indent.
string OptionIndentIncrement::apply(Architecture *glb,const string &p1,const string &p2,const string &p3) const

{
  istringstream s(p1);
  s.unsetf(ios::dec | ios::hex | ios::oct);
  int4 val = -1;
  s >> val;
  if (val==-1)
    throw ParseError("Must specify integer increment");
  glb->print->setIndentIncrement(val);
  return "Characters per indent level set to "+p1;
}

/// \class OptionCommentIndent
/// \brief How many characters to indent comment lines.
///
/// The first parameter gives the integer value.  Comment lines are indented this much independent
/// of the associated code's nesting depth.
string OptionCommentIndent::apply(Architecture *glb,const string &p1,const string &p2,const string &p3) const

{
  istringstream s(p1);
  s.unsetf(ios::dec | ios::hex | ios::oct);
  int4 val = -1;
  s >> val;
  if (val==-1)
    throw ParseError("Must specify integer comment indent");
  glb->print->setLineCommentIndent(val);
  return "Comment indent set to "+p1;
}

/// \class OptionCommentStyle
/// \brief Set the style of comment emitted by the decompiler
///
/// The first parameter is either "c", "cplusplus", a string starting with "/*", or a string starting with "//"
string OptionCommentStyle::apply(Architecture *glb,const string &p1,const string &p2,const string &p3) const

{
  glb->print->setCommentStyle(p1);
  return "Comment style set to "+p1;
}

/// \class OptionCommentHeader
/// \brief Toggle whether different comment \e types are emitted by the decompiler in the header for a function
///
/// The first parameter specifies the comment type: "header" and "warningheader"
/// The second parameter is the toggle value "on" or "off".
string OptionCommentHeader::apply(Architecture *glb,const string &p1,const string &p2,const string &p3) const

{
  bool toggle = onOrOff(p2);
  uint4 flags = glb->print->getHeaderComment();
  uint4 val = Comment::encodeCommentType(p1);
  if (toggle)
    flags |= val;
  else
    flags &= ~val;
  glb->print->setHeaderComment(flags);
  string prop;
  prop = toggle ? "on" : "off";
  return "Header comment type "+p1+" turned "+prop;
}

/// \class OptionCommentInstruction
/// \brief Toggle whether different comment \e types are emitted by the decompiler in the body of a function
///
/// The first parameter specifies the comment type: "warning", "user1", "user2", etc.
/// The second parameter is the toggle value "on" or "off".
string OptionCommentInstruction::apply(Architecture *glb,const string &p1,const string &p2,const string &p3) const

{
  bool toggle = onOrOff(p2);
  uint4 flags = glb->print->getInstructionComment();
  uint4 val = Comment::encodeCommentType(p1);
  if (toggle)
    flags |= val;
  else
    flags &= ~val;
  glb->print->setInstructionComment(flags);
  string prop;
  prop = toggle ? "on" : "off";
  return "Instruction comment type "+p1+" turned "+prop;
}

/// \class OptionIntegerFormat
/// \brief Set the formatting strategy used by the decompiler to emit integers
///
/// The first parameter is the strategy name: "hex", "dec", or "best"
string OptionIntegerFormat::apply(Architecture *glb,const string &p1,const string &p2,const string &p3) const

{
  glb->print->setIntegerFormat(p1);
  return "Integer format set to "+p1;
}

/// \class OptionSetAction
/// \brief Establish a new root Action for the decompiler
///
/// The first parameter specifies the name of the root Action. If a second parameter
/// is given, it specifies the name of a new root Action, which  is created by copying the
/// Action specified with the first parameter.  In this case, the current root Action is
/// set to the new copy, which can then by modified
string OptionSetAction::apply(Architecture *glb,const string &p1,const string &p2,const string &p3) const

{
  if (p1.size()==0)
    throw ParseError("Must specify preexisting action");

  if (p2.size() != 0) {
    glb->allacts.cloneGroup(p1,p2);
    glb->allacts.setCurrent(p2);
    return "Created "+p2+" by cloning "+p1+" and made it current";
  }
  glb->allacts.setCurrent(p1);
  return "Set current action to "+p1;
}

/// \class OptionCurrentAction
/// \brief Toggle a sub-group of actions within a root Action
///
/// If two parameters are given, the first indicates the name of the sub-group, and the second is
/// the toggle value, "on" or "off". The change is applied to the current root Action.
///
/// If three parameters are given, the first indicates the root Action (which will be set as current)
/// to modify. The second and third parameters give the name of the sub-group and the toggle value.
string OptionCurrentAction::apply(Architecture *glb,const string &p1,const string &p2,const string &p3) const

{
  if ((p1.size()==0)||(p2.size()==0))
    throw ParseError("Must specify subaction, on/off");
  bool val;
  string res = "Toggled ";

  if (p3.size() != 0) {
    glb->allacts.setCurrent(p1);
    val = onOrOff(p3);
    glb->allacts.toggleAction(p1,p2,val);
    res += p2 + " in action "+p1;
  }
  else {
    val = onOrOff(p2);
    glb->allacts.toggleAction(glb->allacts.getCurrentName(),p1,val);
    res += p1 + " in action "+glb->allacts.getCurrentName();
  }

  return res;
}

/// \class OptionAllowContextSet
/// \brief Toggle whether the disassembly engine is allowed to modify context
///
/// If the first parameter is "on", disassembly can make changes to context
string OptionAllowContextSet::apply(Architecture *glb,const string &p1,const string &p2,const string &p3) const

{
  bool val = onOrOff(p1);

  string prop = val ? "on" : "off";
  string res = "Toggled allowcontextset to "+prop;
  glb->translate->allowContextSet(val);

  return res;
}

/// \class OptionIgnoreUnimplemented
/// \brief Toggle whether unimplemented instructions are treated as a \e no-operation
///
/// If the first parameter is "on", unimplemented instructions are ignored, otherwise
/// they are treated as an artificial \e halt in the control flow.
string OptionIgnoreUnimplemented::apply(Architecture *glb,const string &p1,const string &p2,const string &p3) const

{
  bool val = onOrOff(p1);

  string res;
  if (val) {
    res = "Unimplemented instructions are now ignored (treated as nop)";
    glb->flowoptions |= FlowInfo::ignore_unimplemented;
  }
  else {
    res = "Unimplemented instructions now generate warnings";
    glb->flowoptions &= ~((uint4)FlowInfo::ignore_unimplemented);
  }

  return res;
}

/// \class OptionErrorUnimplemented
/// \brief Toggle whether unimplemented  instructions are treated as a fatal error.
///
/// If the first parameter is "on", decompilation of functions with unimplemented instructions
/// will terminate with a fatal error message. Otherwise, warning comments will be generated.
string OptionErrorUnimplemented::apply(Architecture *glb,const string &p1,const string &p2,const string &p3) const

{
  bool val = onOrOff(p1);

  string res;
  if (val) {
    res = "Unimplemented instructions are now a fatal error";
    glb->flowoptions |= FlowInfo::error_unimplemented;
  }
  else {
    res = "Unimplemented instructions now NOT a fatal error";
    glb->flowoptions &= ~((uint4)FlowInfo::error_unimplemented);
  }

  return res;
}

/// \class OptionErrorReinterpreted
/// \brief Toggle whether off-cut reinterpretation of an instruction is a fatal error
///
/// If the first parameter is "on", interpreting the same code bytes at two or more different
/// \e cuts, during disassembly, is considered a fatal error.
string OptionErrorReinterpreted::apply(Architecture *glb,const string &p1,const string &p2,const string &p3) const

{
  bool val = onOrOff(p1);

  string res;
  if (val) {
    res = "Instruction reinterpretation is now a fatal error";
    glb->flowoptions |= FlowInfo::error_reinterpreted;
  }
  else {
    res = "Instruction reinterpretation is now NOT a fatal error";
    glb->flowoptions &= ~((uint4)FlowInfo::error_reinterpreted);
  }

  return res;
}
/// \class OptionErrorTooManyInstructions
/// \brief Toggle whether too many instructions in one function body is considered a fatal error.
///
/// If the first parameter is "on" and the number of instructions in a single function body exceeds
/// the threshold, then decompilation will halt for that function with a fatal error. Otherwise,
/// artificial halts are generated to prevent control-flow into further instructions.
string OptionErrorTooManyInstructions::apply(Architecture *glb,const string &p1,const string &p2,const string &p3) const

{
  bool val = onOrOff(p1);

  string res;
  if (val) {
    res = "Too many instructions are now a fatal error";
    glb->flowoptions |= FlowInfo::error_toomanyinstructions;
  }
  else {
    res = "Too many instructions are now NOT a fatal error";
    glb->flowoptions &= ~((uint4)FlowInfo::error_toomanyinstructions);
  }

  return res;
}

/// \class OptionProtoEval
/// \brief Set the prototype model to use when evaluating the parameters of the \e current function
///
/// The first parameter gives the name of the prototype model. The string "default" can be given
/// to refer to the format \e default model for the architecture. The specified model is used to
/// evaluate parameters of the function actively being decompiled, which may be distinct from the
/// model used to evaluate sub-functions.
string OptionProtoEval::apply(Architecture *glb,const string &p1,const string &p2,const string &p3) const

{
  ProtoModel *model = (ProtoModel *)0;
  
  if (p1.size()==0)
    throw ParseError("Must specify prototype model");

  if (p1 == "default")
    model = glb->defaultfp;
  else {
    model = glb->protoModels[p1];
    if (model == (ProtoModel *)0)
      throw ParseError("Unknown prototype model: "+p1);
  }
  string res = "Set current evaluation to " + p1;
  glb->evalfp_current = model;
  return res;
}

/// \class OptionSetLanguage
/// \brief Set the current language emitted by the decompiler
///
/// The first specifies the name of the language to emit: "c-language", "java-language", etc.
string OptionSetLanguage::apply(Architecture *glb,const string &p1,const string &p2,const string &p3) const

{
  string res;

  glb->setPrintLanguage(p1);
  res = "Decompiler produces "+p1;
  return res;
}

/// \class OptionJumpLoad
/// \brief Toggle whether the decompiler should try to recover the table used to evaluate a switch
///
/// If the first parameter is "on", the decompiler will record the memory locations with constant values
/// that were accessed as part of the jump-table so that they can be formally labeled.
string OptionJumpLoad::apply(Architecture *glb,const string &p1,const string &p2,const string &p3) const

{
  bool val = onOrOff(p1);

  string res;
  if (val) {
    res = "Jumptable analysis will record loads required to calculate jump address";
    glb->flowoptions |= FlowInfo::record_jumploads;
  }
  else {
    res = "Jumptable analysis will NOT record loads";
    glb->flowoptions &= ~((uint4)FlowInfo::record_jumploads);
  }
  return res;
}

/// \class OptionToggleRule
/// \brief Toggle whether a specific Rule is applied in the current Action
///
/// The first parameter must be a name \e path describing the unique Rule instance
/// to be toggled.  The second parameter is "on" to \e enable the Rule, "off" to \e disable.
string OptionToggleRule::apply(Architecture *glb,const string &p1,const string &p2,const string &p3) const

{
  if (p1.size() == 0)
    throw ParseError("Must specify rule path");
  if (p2.size() == 0)
    throw ParseError("Must specify on/off");
  bool val = onOrOff(p2);

  Action *root = glb->allacts.getCurrent();
  if (root == (Action *)0)
    throw LowlevelError("Missing current action");
  string res;
  if (!val) {
    if (root->disableRule(p1))
      res = "Successfully disabled";
    else
      res = "Failed to disable";
    res += " rule";
  }
  else {
    if (root->enableRule(p1))
      res = "Successfully enabled";
    else
      res = "Failed to enable";
    res += " rule";
  }
  return res;
}

/// \class OptionAliasBlock
/// \brief Set how locked data-types on the stack affect alias heuristics
///
/// Stack analysis uses the following simple heuristic: a pointer is unlikely to reference (alias)
/// a stack location if there is a locked data-type between the pointer base and the location.
/// This option determines what kind of locked data-types \b block aliases in this way.
///   - none - no data-types will block an alias
///   - struct - only structure data-types will block an alias
///   - array - array data-types (and structure data-types) will block an alias
///   - all - all locked data-types will block an alias
string OptionAliasBlock::apply(Architecture *glb,const string &p1,const string &p2,const string &p3) const

{
  if (p1.size() == 0)
    throw ParseError("Must specify alias block level");
  int4 oldVal = glb->alias_block_level;
  if (p1 == "none")
    glb->alias_block_level = 0;
  else if (p1 == "struct")
    glb->alias_block_level = 1;
  else if (p1 == "array")
    glb->alias_block_level = 2;		// The default. Let structs and arrays block aliases
  else if (p1 == "all")
    glb->alias_block_level = 3;
  else
    throw ParseError("Unknown alias block level: "+p1);
  if (oldVal == glb->alias_block_level)
    return "Alias block level unchanged";
  return "Alias block level set to " + p1;
}

/// \class OptionMaxInstruction
/// \brief Maximum number of instructions that can be processed in a single function
///
/// The first parameter is an integer specifying the maximum.
string OptionMaxInstruction::apply(Architecture *glb,const string &p1,const string &p2,const string &p3) const

{
  if (p1.size() == 0)
    throw ParseError("Must specify number of instructions");

  int4 newMax = -1;
  istringstream s1(p1);
  s1.unsetf(ios::dec | ios::hex | ios::oct); // Let user specify base
  s1 >> newMax;
  if (newMax < 0)
    throw ParseError("Bad maxinstruction parameter");
  glb->max_instructions = newMax;
  return "Maximum instructions per function set";
}

/// \class OptionNamespaceStrategy
/// \brief How should namespace tokens be displayed
///
/// The first parameter gives the strategy identifier, mapping to PrintLanguage::namespace_strategy.
string OptionNamespaceStrategy::apply(Architecture *glb,const string &p1,const string &p2,const string &p3) const

{
  PrintLanguage::namespace_strategy strategy;
  if (p1 == "minimal")
    strategy = PrintLanguage::MINIMAL_NAMESPACES;
  else if (p1 == "all")
    strategy = PrintLanguage::ALL_NAMESPACES;
  else if (p1 == "none")
    strategy = PrintLanguage::NO_NAMESPACES;
  else
    throw ParseError("Must specify a valid strategy");
  glb->print->setNamespaceStrategy(strategy);
  return "Namespace strategy set";
}