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
/* ###
 * 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 "sleigh.hh"
#include "loadimage.hh"

PcodeCacher::PcodeCacher(void)

{
  // We aim to allocate this array only once
  uint4 maxsize = 600;
  poolstart = new VarnodeData[ maxsize ];
  endpool = poolstart + maxsize;
  curpool = poolstart;
}

PcodeCacher::~PcodeCacher(void)

{
  delete [] poolstart;
}

/// Expand the VarnodeData pool so that \e size more elements fit, and return
/// a pointer to first available element.
/// \param size is the number of elements to expand the pool by
/// \return the first available VarnodeData
VarnodeData *PcodeCacher::expandPool(uint4 size)

{
  uint4 curmax = endpool - poolstart;
  uint4 cursize = curpool - poolstart;
  if (cursize + size <= curmax)
    return curpool;		// No expansion necessary
  uint4 increase = (cursize + size) - curmax;
  if (increase < 100)		// Increase by at least 100
    increase = 100;

  uint4 newsize = curmax + increase;

  VarnodeData *newpool = new VarnodeData[newsize];
  for(uint4 i=0;i<cursize;++i)
    newpool[i] = poolstart[i];	// Copy old data
  // Update references to the old pool
  for(uint4 i=0;i<issued.size();++i) {
    VarnodeData *outvar = issued[i].outvar;
    if (outvar != (VarnodeData *)0) {
      outvar = newpool + (outvar - poolstart);
      issued[i].outvar = outvar;
    }
    VarnodeData *invar = issued[i].invar;
    if (invar != (VarnodeData *)0) {
      invar = newpool + (invar - poolstart);
      issued[i].invar = invar;
    }
  }
  list<RelativeRecord>::iterator iter;
  for(iter=label_refs.begin();iter!=label_refs.end();++iter) {
    VarnodeData *ref = (*iter).dataptr;
    (*iter).dataptr = newpool + (ref - poolstart);
  }
  
  delete [] poolstart;		// Free up old pool
  poolstart = newpool;
  curpool = newpool + (cursize + size);
  endpool = newpool + newsize;
  return newpool + cursize;
}

/// Store off a reference to the Varnode and the absolute index of the next
/// instruction.  The Varnode must be an operand of the current instruction.
/// \param ptr is the Varnode reference
void PcodeCacher::addLabelRef(VarnodeData *ptr)

{
  label_refs.emplace_back();
  label_refs.back().dataptr = ptr;
  label_refs.back().calling_index = issued.size();
}

/// The label has an id that is referred to by Varnodes holding
/// intra-instruction branch targets, prior to converting
/// them to a \e relative \e branch offset.  The label is associated with
/// the absolute index of the next PcodeData object to be issued,
/// facilitating this conversion.
/// \param id is the given id of the label
void PcodeCacher::addLabel(uint4 id)

{
  while(labels.size() <= id)
    labels.push_back(0xbadbeef);
  labels[ id ] = issued.size();
}

void PcodeCacher::clear(void)

{
  curpool = poolstart;
  issued.clear();
  label_refs.clear();
  labels.clear();
}

/// Assuming all the PcodeData has been generated for an
/// instruction, go resolve any relative offsets and back
/// patch their value(s) into the PcodeData
void PcodeCacher::resolveRelatives(void)

{
  list<RelativeRecord>::const_iterator iter;
  for(iter=label_refs.begin();iter!=label_refs.end();++iter) {
    VarnodeData *ptr = (*iter).dataptr;
    uint4 id = ptr->offset;
    if ((id >= labels.size())||(labels[id] == 0xbadbeef))
      throw LowlevelError("Reference to non-existant sleigh label");
    // Calculate the relative index given the two absolute indices
    uintb res = labels[id] - (*iter).calling_index;
    res &= calc_mask( ptr->size );
    ptr->offset = res;
  }
}

/// Each p-code operation is presented to the emitter via its dump() method.
/// \param addr is the Address associated with the p-code operation
/// \param emt is the emitter
void PcodeCacher::emit(const Address &addr,PcodeEmit *emt) const

{
  vector<PcodeData>::const_iterator iter;

  for(iter=issued.begin();iter!=issued.end();++iter)
    emt->dump(addr,(*iter).opc,(*iter).outvar,(*iter).invar,(*iter).isize);
}

/// \brief Generate a concrete VarnodeData object from the given template (VarnodeTpl)
///
/// \param vntpl is the template to reference
/// \param vn is the object to fill in with concrete values
void SleighBuilder::generateLocation(const VarnodeTpl *vntpl,VarnodeData &vn)

{
  vn.space = vntpl->getSpace().fixSpace(*walker);
  vn.size = vntpl->getSize().fix(*walker);
  if (vn.space == const_space)
    vn.offset = vntpl->getOffset().fix(*walker) & calc_mask(vn.size);
  else if (vn.space == uniq_space) {
    vn.offset = vntpl->getOffset().fix(*walker);
    vn.offset |= uniqueoffset;
  }
  else
    vn.offset = vn.space->wrapOffset(vntpl->getOffset().fix(*walker));
}

/// \brief Generate a pointer VarnodeData from a dynamic template (VarnodeTpl)
///
/// The symbol represents a value referenced through a dynamic pointer.
/// This method generates the varnode representing the pointer itself and also
/// returns the address space in anticipation of generating the LOAD or STORE
/// that actually manipulates the value.
/// \param vntpl is the dynamic template to reference
/// \param vn is the object to fill with concrete values
/// \return the address space being pointed to
AddrSpace *SleighBuilder::generatePointer(const VarnodeTpl *vntpl,VarnodeData &vn)

{
  const FixedHandle &hand(walker->getFixedHandle(vntpl->getOffset().getHandleIndex()));
  vn.space = hand.offset_space;
  vn.size = hand.offset_size;
  if (vn.space == const_space)
    vn.offset = hand.offset_offset & calc_mask(vn.size);
  else if (vn.space == uniq_space)
    vn.offset = hand.offset_offset | uniqueoffset;
  else
    vn.offset = vn.space->wrapOffset(hand.offset_offset);
  return hand.space;
}

void SleighBuilder::generatePointerAdd(PcodeData *op,const VarnodeTpl *vntpl)

{
  uintb offsetPlus = vntpl->getOffset().getReal() & 0xffff;
  if (offsetPlus == 0) {
    return;
  }
  PcodeData *nextop = cache->allocateInstruction();
  nextop->opc = op->opc;
  nextop->invar = op->invar;
  nextop->isize = op->isize;
  nextop->outvar = op->outvar;
  op->isize = 2;
  op->opc = CPUI_INT_ADD;
  VarnodeData *newparams = op->invar = cache->allocateVarnodes(2);
  newparams[0] = nextop->invar[1];
  newparams[1].space = const_space;	// Add in V_OFFSET_PLUS
  newparams[1].offset = offsetPlus;
  newparams[1].size = newparams[0].size;
  op->outvar = nextop->invar + 1;	// Output of ADD is input to original op
  op->outvar->space = uniq_space;		// Result of INT_ADD in special runtime temp
  op->outvar->offset = uniq_space->getTrans()->getUniqueStart(Translate::RUNTIME_BITRANGE_EA);
}

void SleighBuilder::dump(OpTpl *op)

{				// Dump on op through low-level dump interface
				// filling in dynamic loads and stores if necessary
  PcodeData *thisop;
  VarnodeData *invars;
  VarnodeData *loadvars;
  VarnodeData *storevars;
  VarnodeTpl *vn,*outvn;
  int4 isize = op->numInput();
				// First build all the inputs
  invars = cache->allocateVarnodes(isize);
  for(int4 i=0;i<isize;++i) {
    vn = op->getIn(i);
    if (vn->isDynamic(*walker)) {
      generateLocation(vn,invars[i]); // Input of -op- is really temporary storage
      PcodeData *load_op = cache->allocateInstruction();
      load_op->opc = CPUI_LOAD;
      load_op->outvar = invars + i;
      load_op->isize = 2;
      loadvars = load_op->invar = cache->allocateVarnodes(2);
      AddrSpace *spc = generatePointer(vn,loadvars[1]);
      loadvars[0].space = const_space;
      loadvars[0].offset = (uintb)(uintp)spc;
      loadvars[0].size = sizeof(spc);
      if (vn->getOffset().getSelect() == ConstTpl::v_offset_plus)
	generatePointerAdd(load_op, vn);
    }
    else
      generateLocation(vn,invars[i]);
  }
  if ((isize>0)&&(op->getIn(0)->isRelative())) {
    invars->offset += getLabelBase();
    cache->addLabelRef(invars);
  }
  thisop = cache->allocateInstruction();
  thisop->opc = op->getOpcode();
  thisop->invar = invars;
  thisop->isize = isize;
  outvn = op->getOut();
  if (outvn != (VarnodeTpl *)0) {
    if (outvn->isDynamic(*walker)) {
      storevars = cache->allocateVarnodes(3);
      generateLocation(outvn,storevars[2]); // Output of -op- is really temporary storage
      thisop->outvar = storevars+2;
      PcodeData *store_op = cache->allocateInstruction();
      store_op->opc = CPUI_STORE;
      store_op->isize = 3;
      // store_op->outvar = (VarnodeData *)0;
      store_op->invar = storevars;
      AddrSpace *spc = generatePointer(outvn,storevars[1]); // pointer
      storevars[0].space = const_space;
      storevars[0].offset = (uintb)(uintp)spc; // space in which to store
      storevars[0].size = sizeof(spc);
      if (outvn->getOffset().getSelect() == ConstTpl::v_offset_plus)
	generatePointerAdd(store_op,outvn);
    }
    else {
      thisop->outvar = cache->allocateVarnodes(1);
      generateLocation(outvn,*thisop->outvar);
    }
  }
}

/// \brief Build a named p-code section of a constructor that contains only implied BUILD directives
///
/// If a named section of a constructor is empty, we still need to walk
/// through any subtables that might contain p-code in their named sections.
/// This method treats each subtable operand as an implied \e build directive,
/// in the otherwise empty section.
/// \param ct is the matching currently Constructor being built
/// \param secnum is the particular \e named section number to build
void SleighBuilder::buildEmpty(Constructor *ct,int4 secnum)

{
  int4 numops = ct->getNumOperands();
  
  for(int4 i=0;i<numops;++i) {
    SubtableSymbol *sym = (SubtableSymbol *)ct->getOperand(i)->getDefiningSymbol();
    if (sym == (SubtableSymbol *)0) continue;
    if (sym->getType() != SleighSymbol::subtable_symbol) continue;

    walker->pushOperand(i);
    ConstructTpl *construct = walker->getConstructor()->getNamedTempl(secnum);
    if (construct == (ConstructTpl *)0)
      buildEmpty(walker->getConstructor(),secnum);
    else
      build(construct,secnum);
    walker->popOperand();
  }
}

/// Bits used to make temporary registers unique across multiple instructions
/// are generated based on the given address.
/// \param addr is the given Address
void SleighBuilder::setUniqueOffset(const Address &addr)

{
  uniqueoffset = (addr.getOffset() & uniquemask)<<4;
}

/// \brief Constructor
///
/// \param w is the parsed instruction
/// \param dcache is a cache of nearby instruction parses
/// \param pc will hold the PcodeData and VarnodeData objects produced by \b this builder
/// \param cspc is the constant address space
/// \param uspc is the unique address space
/// \param umask is the mask to use to find unique bits within an Address
SleighBuilder::SleighBuilder(ParserWalker *w,DisassemblyCache *dcache,PcodeCacher *pc,AddrSpace *cspc,
			     AddrSpace *uspc,uint4 umask)
  : PcodeBuilder(0)
{
  walker = w;
  discache = dcache;
  cache = pc;
  const_space = cspc;
  uniq_space = uspc;
  uniquemask = umask;
  uniqueoffset = (walker->getAddr().getOffset() & uniquemask)<<4;
}

void SleighBuilder::appendBuild(OpTpl *bld,int4 secnum)

{
  // Append p-code for a particular build statement
  int4 index = bld->getIn(0)->getOffset().getReal(); // Recover operand index from build statement
				// Check if operand is a subtable
  SubtableSymbol *sym = (SubtableSymbol *)walker->getConstructor()->getOperand(index)->getDefiningSymbol();
  if ((sym==(SubtableSymbol *)0)||(sym->getType() != SleighSymbol::subtable_symbol)) return;
  
  walker->pushOperand(index);
  Constructor *ct = walker->getConstructor();
  if (secnum >=0) {
    ConstructTpl *construct = ct->getNamedTempl(secnum);
    if (construct == (ConstructTpl *)0)
      buildEmpty(ct,secnum);
    else
      build(construct,secnum);
  }
  else {
    ConstructTpl *construct = ct->getTempl();
    build(construct,-1);
  }
  walker->popOperand();
}

void SleighBuilder::delaySlot(OpTpl *op)

{
  // Append pcode for an entire instruction (delay slot)
  // in the middle of the current instruction
  ParserWalker *tmp = walker;
  uintb olduniqueoffset = uniqueoffset;

  Address baseaddr = tmp->getAddr();
  int4 fallOffset = tmp->getLength();
  int4 delaySlotByteCnt = tmp->getParserContext()->getDelaySlot();
  int4 bytecount = 0;
  do {
    Address newaddr = baseaddr + fallOffset;
    setUniqueOffset(newaddr);
    const ParserContext *pos = discache->getParserContext(newaddr);
    if (pos->getParserState() != ParserContext::pcode)
      throw LowlevelError("Could not obtain cached delay slot instruction");
    int4 len = pos->getLength();

    ParserWalker newwalker( pos );
    walker = &newwalker;
    walker->baseState();
    build(walker->getConstructor()->getTempl(),-1); // Build the whole delay slot
    fallOffset += len;
    bytecount += len;
  } while(bytecount < delaySlotByteCnt);
  walker = tmp;			// Restore original context
  uniqueoffset = olduniqueoffset;
}

void SleighBuilder::setLabel(OpTpl *op)

{
  cache->addLabel( op->getIn(0)->getOffset().getReal()+getLabelBase() );
}

void SleighBuilder::appendCrossBuild(OpTpl *bld,int4 secnum)

{
  // Weave in the p-code section from an instruction at another address
  // bld-param(0) contains the address of the instruction
  // bld-param(1) contains the section number
  if (secnum>=0)
    throw LowlevelError("CROSSBUILD directive within a named section");
  secnum = bld->getIn(1)->getOffset().getReal();
  VarnodeTpl *vn = bld->getIn(0);
  AddrSpace *spc = vn->getSpace().fixSpace(*walker);
  uintb addr = spc->wrapOffset( vn->getOffset().fix(*walker) );

  ParserWalker *tmp = walker;
  uintb olduniqueoffset = uniqueoffset;

  Address newaddr(spc,addr);
  setUniqueOffset(newaddr);
  const ParserContext *pos = discache->getParserContext( newaddr );
  if (pos->getParserState() != ParserContext::pcode)
    throw LowlevelError("Could not obtain cached crossbuild instruction");
  
  ParserWalker newwalker( pos, tmp->getParserContext() );
  walker = &newwalker;

  walker->baseState();
  Constructor *ct = walker->getConstructor();
  ConstructTpl *construct = ct->getNamedTempl(secnum);
  if (construct == (ConstructTpl *)0)
    buildEmpty(ct,secnum);
  else
    build(construct,secnum);
  walker = tmp;
  uniqueoffset = olduniqueoffset;
}

/// \param min is the minimum number of allocations before a reuse is expected
/// \param hashsize is the number of elements in the hash-table
void DisassemblyCache::initialize(int4 min,int4 hashsize)

{
  minimumreuse = min;
  mask = hashsize-1;
  uintb masktest = coveringmask((uintb)mask);
  if (masktest != (uintb)mask)	// -hashsize- must be a power of 2
    throw LowlevelError("Bad windowsize for disassembly cache");
  list = new ParserContext *[minimumreuse];
  nextfree = 0;
  hashtable = new ParserContext *[hashsize];
  for(int4 i=0;i<minimumreuse;++i) {
    ParserContext *pos = new ParserContext(contextcache);
    pos->initialize(75,20,constspace);
    list[i] = pos;
  }
  ParserContext *pos = list[0];
  for(int4 i=0;i<hashsize;++i)
    hashtable[i] = pos;		// Make sure all hashtable positions point to a real ParserContext
}

void DisassemblyCache::free(void)

{
  for(int4 i=0;i<minimumreuse;++i)
    delete list[i];
  delete [] list;
  delete [] hashtable;
}

/// \param ccache is the ContextCache front-end shared across all the parser contexts
/// \param cspace is the constant address space used for minting constant Varnodes
/// \param cachesize is the number of distinct ParserContext objects in this cache
/// \param windowsize is the size of the ParserContext hash-table
DisassemblyCache::DisassemblyCache(ContextCache *ccache,AddrSpace *cspace,int4 cachesize,int4 windowsize)

{
  contextcache = ccache;
  constspace = cspace;
  initialize(cachesize,windowsize);		// Set default settings for the cache
}

/// Return a (possibly cached) ParserContext that is associated with \e addr
/// If n different calls to this interface are made with n different Addresses, if
///    - n <= minimumreuse   AND
///    - all the addresses are within the windowsize (=mask+1)
///
/// then the cacher guarantees that you get all different ParserContext objects
/// \param addr is the Address to disassemble at
/// \return the ParserContext associated with the address
ParserContext *DisassemblyCache::getParserContext(const Address &addr)

{
  int4 hashindex = ((int4) addr.getOffset()) & mask;
  ParserContext *res = hashtable[ hashindex ];
  if (res->getAddr() == addr)
    return res;
  res = list[ nextfree ];
  nextfree += 1;		// Advance the circular index
  if (nextfree >= minimumreuse)
    nextfree = 0;
  res->setAddr(addr);
  res->setParserState(ParserContext::uninitialized);	// Need to start over with parsing
  hashtable[ hashindex ] = res;	// Stick it into the hashtable
  return res;
}

/// \param ld is the LoadImage to draw program bytes from
/// \param c_db is the context database
Sleigh::Sleigh(LoadImage *ld,ContextDatabase *c_db)
  : SleighBase()

{
  loader = ld;
  context_db = c_db;
  cache = new ContextCache(c_db);
  discache = (DisassemblyCache *)0;
}

void Sleigh::clearForDelete(void)

{
  delete cache;
  if (discache != (DisassemblyCache *)0)
    delete discache;
}

Sleigh::~Sleigh(void)

{
  clearForDelete();
}

/// Completely clear everything except the base and reconstruct
/// with a new LoadImage and ContextDatabase
/// \param ld is the new LoadImage
/// \param c_db is the new ContextDatabase
void Sleigh::reset(LoadImage *ld,ContextDatabase *c_db)

{
  clearForDelete();
  pcode_cache.clear();
  loader = ld;
  context_db = c_db;
  cache = new ContextCache(c_db);
  discache = (DisassemblyCache *)0;
}

/// The .sla file from the document store is loaded and cache objects are prepared
/// \param store is the document store containing the main \<sleigh> tag.
void Sleigh::initialize(DocumentStorage &store)

{
  if (!isInitialized()) {	// Initialize the base if not already
    const Element *el = store.getTag("sleigh");
    if (el == (const Element *)0)
      throw LowlevelError("Could not find sleigh tag");
    restoreXml(el);
  }
  else
    reregisterContext();
  uint4 parser_cachesize = 2;
  uint4 parser_windowsize = 32;
  if ((maxdelayslotbytes > 1)||(unique_allocatemask != 0)) {
    parser_cachesize = 8;
    parser_windowsize = 256;
  }
  discache = new DisassemblyCache(cache,getConstantSpace(),parser_cachesize,parser_windowsize);
}

/// \brief Obtain a parse tree for the instruction at the given address
///
/// The tree may be cached from a previous access.  If the address
/// has not been parsed, disassembly is performed, and a new parse tree
/// is prepared.  Depending on the desired \e state, the parse tree
/// can be prepared either for disassembly or for p-code generation.
/// \param addr is the given address of the instruction
/// \param state is the desired parse state.
/// \return the parse tree object (ParseContext)
ParserContext *Sleigh::obtainContext(const Address &addr,int4 state) const

{
  ParserContext *pos = discache->getParserContext(addr);
  int4 curstate = pos->getParserState();
  if (curstate >= state)
    return pos;
  if (curstate == ParserContext::uninitialized) {
    resolve(*pos);
    if (state == ParserContext::disassembly)
      return pos;
  }
  // If we reach here,  state must be ParserContext::pcode
  resolveHandles(*pos);
  return pos;
}

/// Resolve \e all the constructors involved in the instruction at the indicated address
/// \param pos is the parse object that will hold the resulting tree
void Sleigh::resolve(ParserContext &pos) const

{
  loader->loadFill(pos.getBuffer(),16,pos.getAddr());
  ParserWalkerChange walker(&pos);
  pos.deallocateState(walker);	// Clear the previous resolve and initialize the walker
  Constructor *ct,*subct;
  uint4 off;
  int4 oper,numoper;

  pos.setDelaySlot(0);
  walker.setOffset(0);		// Initial offset
  pos.clearCommits();		// Clear any old context commits
  pos.loadContext();		// Get context for current address
  ct = root->resolve(walker);	// Base constructor
  walker.setConstructor(ct);
  ct->applyContext(walker);
  while(walker.isState()) {
    ct = walker.getConstructor();
    oper = walker.getOperand();
    numoper = ct->getNumOperands();
    while(oper < numoper) {
      OperandSymbol *sym = ct->getOperand(oper);
      off = walker.getOffset(sym->getOffsetBase()) + sym->getRelativeOffset();
      pos.allocateOperand(oper,walker); // Descend into new operand and reserve space
      walker.setOffset(off);
      TripleSymbol *tsym = sym->getDefiningSymbol();
      if (tsym != (TripleSymbol *)0) {
	subct = tsym->resolve(walker);
	if (subct != (Constructor *)0) {
	  walker.setConstructor(subct);
	  subct->applyContext(walker);
	  break;
	}
      }
      walker.setCurrentLength(sym->getMinimumLength());
      walker.popOperand();
      oper += 1;
    }
    if (oper >= numoper) { // Finished processing constructor
      walker.calcCurrentLength(ct->getMinimumLength(),numoper);
      walker.popOperand();
				// Check for use of delayslot
      ConstructTpl *templ = ct->getTempl();
      if ((templ != (ConstructTpl *)0)&&(templ->delaySlot() > 0))
	pos.setDelaySlot(templ->delaySlot());
    }
  }
  pos.setNaddr(pos.getAddr()+pos.getLength());	// Update Naddr to pointer after instruction
  pos.setParserState(ParserContext::disassembly);
}

/// Resolve handle templates for the given parse tree, assuming Constructors
/// are already resolved.
/// \param pos is the given parse tree
void Sleigh::resolveHandles(ParserContext &pos) const

{
  TripleSymbol *triple;
  Constructor *ct;
  int4 oper,numoper;

  ParserWalker walker(&pos);
  walker.baseState();
  while(walker.isState()) {
    ct = walker.getConstructor();
    oper = walker.getOperand();
    numoper = ct->getNumOperands();
    while(oper < numoper) {
      OperandSymbol *sym = ct->getOperand(oper);
      walker.pushOperand(oper);	// Descend into node
      triple = sym->getDefiningSymbol();
      if (triple != (TripleSymbol *)0) {
	if (triple->getType() == SleighSymbol::subtable_symbol)
	  break;
	else			// Some other kind of symbol as an operand
	  triple->getFixedHandle(walker.getParentHandle(),walker);
      }
      else {			// Must be an expression
	PatternExpression *patexp = sym->getDefiningExpression();
	intb res = patexp->getValue(walker);
	FixedHandle &hand(walker.getParentHandle());
	hand.space = pos.getConstSpace(); // Result of expression is a constant
	hand.offset_space = (AddrSpace *)0;
	hand.offset_offset = (uintb)res;
	hand.size = 0;		// This size should not get used
      }
      walker.popOperand();
      oper += 1;
    }
    if (oper >= numoper) {	// Finished processing constructor
      ConstructTpl *templ = ct->getTempl();
      if (templ != (ConstructTpl *)0) {
	HandleTpl *res = templ->getResult();
	if (res != (HandleTpl *)0)	// Pop up handle to containing operand
	  res->fix(walker.getParentHandle(),walker);
	// If we need an indicator that the constructor exports nothing try
        // else
	//   walker.getParentHandle().setInvalid();
      }
      walker.popOperand();
    }
  }
  pos.setParserState(ParserContext::pcode);
}

int4 Sleigh::instructionLength(const Address &baseaddr) const

{
  ParserContext *pos = obtainContext(baseaddr,ParserContext::disassembly);
  return pos->getLength();
}

int4 Sleigh::printAssembly(AssemblyEmit &emit,const Address &baseaddr) const

{
  int4 sz;

  ParserContext *pos = obtainContext(baseaddr,ParserContext::disassembly);
  ParserWalker walker(pos);
  walker.baseState();
  
  Constructor *ct = walker.getConstructor();
  ostringstream mons;
  ct->printMnemonic(mons,walker);
  ostringstream body;
  ct->printBody(body,walker);
  emit.dump(baseaddr,mons.str(),body.str());
  sz = pos->getLength();
  return sz;
}

int4 Sleigh::oneInstruction(PcodeEmit &emit,const Address &baseaddr) const

{
  int4 fallOffset;
  if (alignment != 1) {
    if ((baseaddr.getOffset() % alignment)!=0) {
      ostringstream s;
      s << "Instruction address not aligned: " << baseaddr;
      throw UnimplError(s.str(),0);
    }
  }
  
  ParserContext *pos = obtainContext(baseaddr,ParserContext::pcode);
  pos->applyCommits();
  fallOffset = pos->getLength();
  
  if (pos->getDelaySlot()>0) {
    int4 bytecount = 0;
    do {
    // Do not pass pos->getNaddr() to obtainContext, as pos may have been previously cached and had naddr adjusted
      ParserContext *delaypos = obtainContext(pos->getAddr() + fallOffset,ParserContext::pcode);
      delaypos->applyCommits();
      int4 len = delaypos->getLength();
      fallOffset += len;
      bytecount += len;
    } while(bytecount < pos->getDelaySlot());
    pos->setNaddr(pos->getAddr()+fallOffset);
  }
  ParserWalker walker(pos);
  walker.baseState();
  pcode_cache.clear();
  SleighBuilder builder(&walker,discache,&pcode_cache,getConstantSpace(),getUniqueSpace(),unique_allocatemask);
  try {
    builder.build(walker.getConstructor()->getTempl(),-1);
    pcode_cache.resolveRelatives();
    pcode_cache.emit(baseaddr,&emit);
  } catch(UnimplError &err) {
    ostringstream s;
    s << "Instruction not implemented in pcode:\n ";
    ParserWalker *cur = builder.getCurrentWalker();
    cur->baseState();
    Constructor *ct = cur->getConstructor();
    cur->getAddr().printRaw(s);
    s << ": ";
    ct->printMnemonic(s,*cur);
    s << "  ";
    ct->printBody(s,*cur);
    err.explain = s.str();
    err.instruction_length = fallOffset;
    throw err;
  }
  return fallOffset;
}

void Sleigh::registerContext(const string &name,int4 sbit,int4 ebit)

{
  context_db->registerVariable(name,sbit,ebit);
}

void Sleigh::setContextDefault(const string &name,uintm val)

{
  context_db->setVariableDefault(name,val);
}

void Sleigh::allowContextSet(bool val) const

{
  cache->allowSet(val);
}