Update copyright to LGPL on all files
[dyninst.git] / dyninstAPI / src / InstrucIter-ia64.C
1 /*
2  * Copyright (c) 1996-2009 Barton P. Miller
3  * 
4  * We provide the Paradyn Parallel Performance Tools (below
5  * described as "Paradyn") on an AS IS basis, and do not warrant its
6  * validity or performance.  We reserve the right to update, modify,
7  * or discontinue this software at any time.  We shall have no
8  * obligation to supply such updates or modifications or any other
9  * form of support to you.
10  * 
11  * By your use of Paradyn, you understand and agree that we (or any
12  * other person or entity with proprietary rights in Paradyn) are
13  * under no obligation to provide either maintenance services,
14  * update services, notices of latent defects, or correction of
15  * defects for Paradyn.
16  * 
17  * This library is free software; you can redistribute it and/or
18  * modify it under the terms of the GNU Lesser General Public
19  * License as published by the Free Software Foundation; either
20  * version 2.1 of the License, or (at your option) any later version.
21  * 
22  * This library is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
25  * Lesser General Public License for more details.
26  * 
27  * You should have received a copy of the GNU Lesser General Public
28  * License along with this library; if not, write to the Free Software
29  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
30  */
31
32 /* -*- Mode: C; indent-tabs-mode: true; tab-width: 4 -*- */
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <assert.h>
37 #include <string.h>
38
39 #include "common/h/Types.h"
40 #include "common/h/Vector.h"
41 #include "common/h/Dictionary.h"
42
43 #include "arch.h"
44 #include "util.h"
45 #include "process.h"
46 #include "mapped_object.h"
47 #include "symtab.h"
48 #include "instPoint.h"
49 #include "InstrucIter.h"
50
51 #include "BPatch_Set.h"
52 #include "BPatch_instruction.h"
53 #include "BPatch_memoryAccess_NP.h"
54
55 /* A few utility functions. */
56 int extractInstructionSlot( Address addr ) {
57   return (addr % 16);
58 } /* end extractInstructionSlot */
59
60 bool addressIsValidInsnAddr( Address addr ) {
61   switch( extractInstructionSlot( addr ) ) {
62   case 0: case 1: case 2:
63     return true;
64   default:
65     return false;
66   }
67 } /* end addressIsValidInsnAddr() */
68
69 /* Access the instruction's type through the correct virtual method */
70 instruction::insnType InstrucIter::getInsnType()
71 {
72   instruction::insnType ret;
73
74   instruction *insn = getInsnPtr();
75   ret = insn->getType();
76
77   delete insn;
78   return ret;
79 }
80
81 bool InstrucIter::isAReturnInstruction() {
82
83   switch( getInsnType() ) {
84   case instruction::RETURN: {
85     instruction * itmp = getInsnPtr();
86     if( itmp->getPredicate() == 0 ) { return true; }
87   } break;
88                         
89   default:
90     break;
91   } /* end instruction-type switch */
92                 
93   return false;
94 } /* end isAReturnInstruction() */
95
96 /** is the instruction used to return from the functions,
97     dependent upon a condition register
98     * @param i the instruction value 
99     */
100 bool InstrucIter::isACondReturnInstruction() {
101   switch( getInsnType() ) {
102   case instruction::RETURN: {
103     instruction * itmp = getInsnPtr();
104     if( itmp->getPredicate() != 0 ) {
105       return true;
106     }
107   } break;
108                         
109   default:
110     break;
111   } /* end instruction-type switch */
112                 
113   return false;
114 } /* end isAReturnInstruction() */
115
116 bool InstrucIter::isAIndirectJumpInstruction()
117 {
118   bool ret;
119   instruction * itmp = getInsnPtr();
120   switch( itmp->getType() ) {
121   case instruction::INDIRECT_BRANCH:
122     if( itmp->getPredicate() == 0 ) 
123       ret = true;
124     else 
125       ret = false;
126     break;
127   default:
128     ret = false;
129     break;
130   } /* end instruction-type switch */
131   delete itmp;
132   return ret;
133 }
134
135 bool InstrucIter::isACondBranchInstruction()
136 {
137   bool ret;
138   instruction * itmp = getInsnPtr();
139   switch( itmp->getType() ) {
140   case instruction::DIRECT_BRANCH:
141     /* Not sure if this second case is intended. */
142   case instruction::INDIRECT_BRANCH: 
143     if( itmp->getPredicate() != 0) 
144       ret = true; 
145     else
146       ret = false;
147     break;  
148   case instruction::COND_BRANCH:
149     ret = true;
150     break;
151   default:
152     ret = false;
153     break;
154   } /* end instruction-type switch */
155   delete itmp;
156   return ret;
157 }
158
159 /* We take this to mean a dirct conditional branch which always executes. */
160 bool InstrucIter::isAJumpInstruction()
161 {
162   bool ret;
163   instruction * itmp = getInsnPtr();
164
165   switch( itmp->getType() ) {
166   case instruction::DIRECT_BRANCH:
167     if( itmp->getPredicate() == 0 ) 
168       ret = true;
169     else
170       ret = false;
171     break;
172         
173   default:
174     ret = false;
175     break;
176   } /* end instruction-type switch */
177   delete itmp;
178   return ret;
179 }
180
181 bool InstrucIter::isACallInstruction()
182 {
183   return (getInsnType() == instruction::DIRECT_CALL ||
184           getInsnType() == instruction::INDIRECT_CALL);
185 }
186
187 bool InstrucIter::isAnneal()
188 {
189   assert( 0 );
190   return false;
191 }
192
193 bool InstrucIter::isAnInterruptInstruction()
194 {
195     // TODO: not implemented
196     return false;
197 }
198
199 bool InstrucIter::isAnAbortInstruction()
200 {
201   // FIXME this is sufficient for the common glibc illegal instruction,
202   // but should be more general
203
204   // glibc uses break 0, which is illegal
205
206   return (getInsnType() == instruction::BREAK);
207 }
208
209 bool InstrucIter::isAnAllocInstruction()
210 {
211   return (getInsnType() == instruction::ALLOC);
212 }
213
214 bool InstrucIter::isDelaySlot()
215 {
216   return false;
217 }
218
219 Address InstrucIter::getBranchTargetAddress(bool *)
220 {
221   instruction * itmp = getInsnPtr();
222   Address rawTargetAddress = itmp->getTargetAddress() + current;
223   Address targetAddress = rawTargetAddress - (rawTargetAddress % 0x10);
224   // /* DEBUG */ fprintf( stderr, "Instruction at 0x%lx targets 0x%lx\n", currentAddress, targetAddress );
225   delete itmp;
226   return targetAddress;
227 }
228
229 void initOpCodeInfo() {
230   /* I don't need this for anything. */
231 } /* end initOpCodeInfo() */
232
233 BPatch_memoryAccess* InstrucIter::isLoadOrStore()
234 {
235   assert(instPtr);
236   instruction *insn = getInsnPtr();
237   instruction::insnType type = getInsnType();
238     
239   BPatch_memoryAccess * bpma = NULL;
240     
241   insn_tmpl tmpl = { insn->getMachineCode() };
242   uint8_t size = 0x1 << (tmpl.M1.x6 & 0x3);
243     
244   switch( type ) {
245   case instruction::INTEGER_16_LOAD:
246     size = 16;
247   case instruction::INTEGER_LOAD:
248   case instruction::FP_LOAD:
249     bpma = new BPatch_memoryAccess( insn, current, true, false, size, 0, tmpl.M1.r3, -1 );
250     assert( bpma != NULL );
251     break;
252         
253   case instruction::INTEGER_16_STORE:
254     size = 16;
255   case instruction::INTEGER_STORE:
256   case instruction::FP_STORE:
257     bpma = new BPatch_memoryAccess( insn, current, false, true, size, 0, tmpl.M1.r3, -1 );
258     assert( bpma != NULL );
259     break;
260         
261   case instruction::FP_PAIR_LOAD:
262   case instruction::INTEGER_PAIR_LOAD:
263     /* The load pair instructions encode sizes a little differently. */
264     size = (tmpl.M1.x6 & 0x1) ? 16 : 8;
265     bpma = new BPatch_memoryAccess( insn, current,true, false, size, 0, tmpl.M1.r3, -1 );
266     assert( bpma != NULL );
267     break;
268         
269   case instruction::PREFETCH:
270     bpma = new BPatch_memoryAccess( insn, current,false, false, 0, tmpl.M1.r3, -1, 0, 0, -1, -1, 0, -1, false, 0 );
271     assert( bpma != NULL );
272     break;
273                         
274   default:
275     return BPatch_memoryAccess::none;
276   }
277     
278   return bpma;
279 }
280
281 /* The IA-64 SCRAG defines a pattern similar to POWER's.  At some constant offset
282    from the GP, there's a jump table whose 64-bit entries are offsets from the base
283    address of the table to the target.
284    
285    However, gcc and icc both deviate from the standard.  The jump table entries
286    generated by icc contain offsets from a label inside the originating function,
287    so we look for moves from IP to locate the label.  The entries in a gcc-generated
288    jump table are offsets from themselves, not the base of the table.  If we don't
289    find a move from IP, we assume gcc-style entries.
290    
291    However, there is a construct in glibc that jumps to an address calculated as an
292    offset from the GP (in vfprintf() and vfwprintf(), for example) using code which
293    looks like a jump table computation and follows an unrelated comparison instruction.
294    
295    We therefore look for a sequence like the following:
296    
297    (1) add rTAA = r1, constant
298    [2] ld8 rTA = [rtAA]
299    (3) add rTE = rTA, rVariable ; we also see shladd rTE = rVariable, 3, rTA.
300    (4) ld8 rBase = [rTE]
301    (5) add rT = rBase + rOffset
302    (6) mov brT = rT
303    (7) br  brT
304                 
305    where rOffset is a previously-defined move from IP and a
306   
307    (<4) cmp.ltu pX, pY = rVariable, constant
308                 
309    occurs anywhere before the second add instruction.  (There should also be a branch
310    predicated on pX somewhere, possibly the one last in this sequence.)
311   
312    rOffset is either rTE or, in icc-style tables, the result of a
313   
314    [<5] mov.ip rOffset = ip
315
316    instruction.  The final complication is that the first ld8 instruction is
317    completely absent in shared objects. 
318   
319    Note that we would need true DFA (the kill sets) to determine a lower bound
320    on the locations of either the cmp.ltu or the mov.ip instructions. */
321   
322 bool InstrucIter::getMultipleJumpTargets( BPatch_Set<Address> & targetAddresses ) {
323   /* DEBUG */ parsing_printf( "%s[%d]: examining jump table (@ 0x%lx)\n", __FILE__, __LINE__, current);
324
325   /* Wind up a new iterator.  This would probably be easier with an explicit
326      state table, but for now I don't think a single pattern with many exceptions
327      warrants the infastructural investment. */
328   InstrucIter iter = * this;
329
330   /* Sanity check. */   
331   instruction branchInstruction = iter.getInstruction();
332   if( branchInstruction.getType() != instruction::INDIRECT_BRANCH ) {
333     fprintf( stderr, "%s[%d]: getMultipleJumpTargets() called on an instruction that is not an indirect branch.\n", __FILE__, __LINE__ );
334     return false;
335   }
336
337   /* Which branch register are we looking for?  (AFAIK, always b6, but why not check?) */
338   insn_tmpl bi_tmpl = { branchInstruction.getMachineCode() };
339   uint64_t branchRegister = bi_tmpl.B4.b2;
340         
341         
342   /* Nothing of interest can occur before the previous mov.br instruction;
343      extract registerTarget when we see it. */
344   bool foundMBTR = false;
345   uint64_t registerTarget = 0;
346   for( ; iter.hasPrev(); --iter ) {
347     instruction moveToBR = iter.getInstruction();
348     if( moveToBR.getUnitType() != instruction::I ) { continue; }
349                 
350     insn_tmpl mtbr_tmpl = { moveToBR.getMachineCode() };
351     if( GET_OPCODE( &mtbr_tmpl ) != 0x0
352         || mtbr_tmpl.I21.x3 != 7 
353         || mtbr_tmpl.I21.x != 0 ) { continue; }
354                 
355     if( mtbr_tmpl.I21.b1 != branchRegister ) {
356       /* DEBUG */ parsing_printf( "%s[%d]: found move to branch register with wrong branch registers (0x%lx, not 0x%lx)\n", __FILE__, __LINE__, mtbr_tmpl.I21.b1, branchRegister );
357       continue;
358     }
359                 
360     /* It's the right instruction; extract registerTarget. */
361     /* DEBUG */ parsing_printf( "%s[%d]: located at 0x%lx\n", __FILE__, __LINE__, iter.current );
362     registerTarget = mtbr_tmpl.I21.r2;
363     foundMBTR = true;
364     break;
365   }      
366   if( ! foundMBTR ) {
367     /* DEBUG */ parsing_printf( "%s[%d]: unable to locate move to branch register.\n", __FILE__, __LINE__ );
368     return false;
369   }
370         
371   /* Nothing of interest can occur before the previous add instruction; extract
372      rBase and rOffset when we find it. */
373   bool foundInstruction5 = false;
374   uint64_t registerBase = 0, registerOffset = 0;
375   for( ; iter.hasPrev(); --iter ) {
376     instruction instruction5 = iter.getInstruction();
377         
378     if( instruction5.getUnitType() != instruction::M && instruction5.getUnitType() != instruction::I ) { continue; }
379                 
380     insn_tmpl i5_tmpl = { instruction5.getMachineCode() };
381     if( GET_OPCODE( &i5_tmpl ) != 0x8
382         || i5_tmpl.A1.x2a != 0
383         || i5_tmpl.A1.ve != 0
384         || i5_tmpl.A1.x4 != 0
385         || i5_tmpl.A1.x2b != 0 ) { continue; }
386                 
387     if( i5_tmpl.A1.r1 != registerTarget ) {
388       /* DEBUG */ parsing_printf( "%s[%d]: found an add instruction with the wrong target at 0x%lx (0x%lx, not 0x%lx)\n", __FILE__, __LINE__, iter.current, i5_tmpl.A1.r1, registerTarget );
389       continue;
390     }
391                 
392     /* It's the right instruction; extract registerBase and registerOffset. */
393     /* DEBUG */ parsing_printf( "%s[%d]: located at 0x%lx\n", __FILE__, __LINE__, iter.current );
394     registerBase = i5_tmpl.A1.r2;
395     registerOffset = i5_tmpl.A1.r3;
396     foundInstruction5 = true;
397     break;
398   }
399   if( ! foundInstruction5 ) {
400     /* DEBUG */ parsing_printf( "%s[%d]: unable to locate instruction 5.\n", __FILE__, __LINE__ );
401     return false;
402   }
403         
404
405   /* For simplicity, ignore the potential mov.ip and search for it in a second pass. */
406   Address movFromIPUpperBound = iter.current;
407
408
409   /* We don't actually know which one of registerBase and registerOffset is really the base until
410      we find the previous ld8 into it, which will also give us registerTableEntry. */
411   bool foundInstruction4 = false;
412   uint64_t registerTableEntry = 0;
413   for( ; iter.hasPrev(); --iter ) {
414     instruction instruction4 = iter.getInstruction();
415                 
416     if( instruction4.getUnitType() != instruction::M ) { continue; }
417                 
418     insn_tmpl i4_tmpl = { instruction4.getMachineCode() };
419     if( GET_OPCODE( &i4_tmpl ) != 0x4
420         || i4_tmpl.M1.m != 0x0
421         || i4_tmpl.M1.x != 0x0
422         || (!(i4_tmpl.M1.x6 <= 0x2B && (i4_tmpl.M1.x6 & 0x3) == 0x3)) ) { continue; }
423
424     /* Swap the names, if necessary; see above. */
425     if( i4_tmpl.M1.r1 != registerBase && i4_tmpl.M1.r1 == registerOffset ) {
426       uint64_t temp = registerBase; registerBase = registerOffset; registerOffset = temp;
427     }
428                         
429     if( i4_tmpl.M1.r1 != registerBase ) {
430       /* DEBUG */ parsing_printf( "%s[%d]: found ld8 instruction with wrong target at 0x%lx (0x%lx. not 0x%lx or 0x%lx)\n", __FILE__, __LINE__, i4_tmpl.M1.r1, iter.current, registerBase, registerOffset );
431       continue;
432     }
433                 
434     /* It's the right instruction; extract registerTableEntry. */
435     registerTableEntry = i4_tmpl.M1.r3;
436     /* DEBUG */ parsing_printf( "\tregisterTableEntry %d located at 0x%lx\n", registerTableEntry, iter.current );
437     foundInstruction4 = true;
438     break;
439   }
440   if( ! foundInstruction4 ) {
441     /* DEBUG */ parsing_printf( "%s[%d]: unable to locate instruction 4.\n", __FILE__, __LINE__ );
442     return false;
443   }
444
445   /* Again, for simplicity, save the concurrent search for another pass. */
446   Address cmpltuUpperBound = iter.current;
447
448   /* Extract registerTableAddress and registerVariable from the previous add or shladd instruction. */
449   bool foundInstruction3 = false;
450   uint64_t registerTableAddress = 0, registerVariable = 0;
451   for( ; iter.hasPrev(); --iter ) {
452     instruction instruction3 = iter.getInstruction();
453         
454     if( instruction3.getUnitType() != instruction::M && instruction3.getUnitType() != instruction::I ) { continue; }
455                 
456     insn_tmpl i3_tmpl = { instruction3.getMachineCode() };
457     if( GET_OPCODE( &i3_tmpl ) != 0x8
458         || i3_tmpl.A1.x2a != 0
459         || i3_tmpl.A1.ve != 0 ) { continue; }   
460     if( i3_tmpl.A1.x4 == 0 ) { if( i3_tmpl.A1.x2b != 0 ) { continue; } }
461     else if( i3_tmpl.A1.x4 != 4 ) { continue; }
462                 
463     if( i3_tmpl.A1.r1 != registerTableEntry ) {
464       /* DEBUG */ parsing_printf( "%s[%d]: found an [shl]add instruction with the wrong target at 0x%lx (0x%lx, not 0x%lx)\n", __FILE__, __LINE__, iter.current, i3_tmpl.A1.r1, registerTarget );
465       continue;
466     }
467                 
468     /* It's the right instruction; extract registerTableAddress and registerVariable. */
469     registerTableAddress = i3_tmpl.A1.r3;
470     registerVariable = i3_tmpl.A1.r2; // In the shladd case, this is the correct order.
471     /* DEBUG */ parsing_printf( "\tregisterTableAddress %d located at 0x%lx\n", registerTableAddress, iter.current );
472     foundInstruction3 = true;
473     break;
474   }
475   if( ! foundInstruction3 ) {
476     /* DEBUG */ parsing_printf( "%s[%d]: unable to locate instruction 3.\n", __FILE__, __LINE__ );
477     return false;
478   }
479
480   /* Since we can get false positives looking for the optional ld8 instruction 2, trust to
481      the empirical evidence that the double indirection only happens in the a.out instead. */
482   bool foundInstruction2 = false;
483   uint64_t registerTableAddressAddress = registerTableAddress;
484   image* img = dynamic_cast<image*>(instructions_);
485   process* proc = dynamic_cast<process*>(instructions_);
486   if( (img && img->isAOut()) || (proc && proc->getAOut()->findCodeRangeByAddress( current )) ) {
487     /* We don't actually know which of registerTableAddressAddress and registerVariable really is the address
488        until we find the previous ld8 or add into it, which will give us registerTableAddressAddress or r1. */             
489     for( ; iter.hasPrev(); --iter ) {
490       instruction instruction2 = iter.getInstruction();
491                 
492       if( instruction2.getUnitType() != instruction::M ) { continue; }
493                 
494       insn_tmpl i2_tmpl = { instruction2.getMachineCode() };
495       if(       GET_OPCODE( &i2_tmpl ) != 0x4
496                 || i2_tmpl.M1.m != 0x0
497                 || i2_tmpl.M1.x != 0x0
498                 || (!(i2_tmpl.M1.x6 <= 0x2B && (i2_tmpl.M1.x6 & 0x3) == 0x3)) ) { continue; }
499
500       /* Swap the names, if necessary; see above. */
501       if( i2_tmpl.M1.r1 != registerTableAddress && i2_tmpl.M1.r1 == registerVariable ) {
502         uint64_t temp = registerTableAddress; registerTableAddress = registerVariable; registerVariable = temp;
503       }
504                 
505       if( i2_tmpl.M1.r1 != registerTableAddress ) {
506         /* DEBUG */ parsing_printf( "%s[%d]: found ld8 instruction with the wrong target at 0x%lx (0x%lx, not 0x%lx or 0x%lx)\n", __FILE__, __LINE__, iter.current, i2_tmpl.M1.r1, registerTableAddress, registerVariable );
507         continue;
508       }
509                 
510       /* It's the right instruction; extract registerTableAddressAddress. */
511       registerTableAddressAddress = i2_tmpl.M1.r3;
512       /* DEBUG */ parsing_printf( "%s[%d]: registerTableAddressAddress %d located at 0x%lx\n", __FILE__, __LINE__, 
513                                   registerTableAddressAddress, iter.current );
514       foundInstruction2 = true;
515       break;
516     }
517   } /* end if we're not parsing an a.out. */
518
519
520   /* Find the add with GP instruction.  NOTE: we only check for the addl form. */
521   bool foundAddWithGP = false;
522   uint64_t jumpTableOffset = 0;
523   bool checkFirstInstruction = true;
524   for( ; iter.hasPrev() || checkFirstInstruction; --iter ) {
525     if( ! iter.hasPrev() ) { checkFirstInstruction = false; }
526         
527     instruction addWithGPInstruction = iter.getInstruction();
528                 
529     if( addWithGPInstruction.getUnitType() != instruction::I && addWithGPInstruction.getUnitType() != instruction::M ) { continue; }
530                 
531     insn_tmpl awgpi_tmpl = { addWithGPInstruction.getMachineCode() };
532     if( GET_OPCODE( &awgpi_tmpl ) != 0x9 ) { continue; }
533         
534     if( awgpi_tmpl.A5.r3 != 0x1 ) {
535       /* DEBUG */ parsing_printf( "%s[%d]: found add with GP instruction with the wrong source at 0x%lx (0x%lx, not 0x1)\n", __FILE__, __LINE__, iter.current, awgpi_tmpl.A5.r3 );
536       continue;
537     }
538     if( awgpi_tmpl.A5.r1 != registerTableAddressAddress ) {
539       /* DEBUG */ parsing_printf( "%s[%d]: found add with GP instruction with the wrong target at 0x%lx (0x%lx, not 0x%lx)\n", __FILE__, __LINE__, iter.current, awgpi_tmpl.A5.r1, registerTableAddressAddress );
540       continue;
541     }
542                 
543     /* It's the right instruction; extract jumpTableOffset. */
544     jumpTableOffset = GET_A5_IMM( &awgpi_tmpl );
545     /* DEBUG */ parsing_printf( "%s[%d]: add with GP located at 0x%lx, table offset 0x%lx\n", __FILE__, __LINE__, iter.current,
546                                 jumpTableOffset);
547     foundAddWithGP = true;
548     break;
549   }             
550   if( ! foundAddWithGP ) {
551     /* DEBUG */ parsing_printf( "%s[%d]: failed to find the add with GP instruction.\n", __FILE__, __LINE__ );
552     return false;
553   }
554         
555         
556   /* Calculate the jump table address and extract the targets.
557      Start by obtaining the GP. */
558   Address gpAddress = 0;
559   if( img ) { 
560     gpAddress = img->getObject()->getTOCoffset();
561   }
562   else {
563     pdvector< mapped_object * > m_objs = proc->mappedObjects();
564     for( unsigned i = 0; i < m_objs.size(); i++ ) {
565       void * ptr = m_objs[i]->getPtrToInstruction( current );
566       if( ptr ) {
567         gpAddress = m_objs[i]->parse_img()->getObject()->getTOCoffset();
568         break;
569       }
570     }
571   }
572   if( gpAddress == 0 ) {
573     /* DEBUG */ parsing_printf( "%s[%d]: unable to find GP for jump table at 0x%lx\n", __FILE__, __LINE__, current );
574     return false;
575   }
576
577   Address jumpTableAddressAddress = gpAddress + jumpTableOffset;
578   Address jumpTableAddress = jumpTableAddressAddress;
579   if( img && img->isAOut() && foundInstruction2 ) {
580     void *ptr = img->getPtrToData( jumpTableAddressAddress );
581     if( ! ptr ) { ptr = img->getPtrToDataInText( jumpTableAddressAddress ); }
582     if( !ptr ) {
583       /* DEBUG */ parsing_printf( "%s[%d]: unable to access jump table address pointer\n", __FILE__, __LINE__ );
584       return false;
585     }
586     jumpTableAddress = *((Address *)ptr);
587   }
588   else if( proc && proc->getAOut()->findCodeRangeByAddress( jumpTableAddressAddress ) && foundInstruction2 ) {
589     void * ptr = instructions_->getPtrToInstruction( jumpTableAddressAddress );
590     if( !ptr ) {
591       /* DEBUG */ parsing_printf( "%s[%d]: unable to access jump table address pointer\n", __FILE__, __LINE__ );
592       return false;
593     }
594     jumpTableAddress = *((Address *)ptr);
595   }
596                 
597   /* Check if the jump table is IP-relative. */ 
598   iter.setCurrentAddress( movFromIPUpperBound );
599   bool foundMovFromIP = false;
600   Address baseJumpAddress = jumpTableAddress;
601   for( ; iter.hasPrev(); --iter ) {
602     instruction movFromIP = iter.getInstruction();
603                 
604     if( movFromIP.getUnitType() != instruction::I ) { continue; }
605                 
606     insn_tmpl mfip_tmpl = { movFromIP.getMachineCode() };
607     if( mfip_tmpl.I25.opcode != 0x0
608         || mfip_tmpl.I25.x6 != 0x30
609         || mfip_tmpl.I25.x3 != 0x0 ) { continue; }
610                         
611     /* It's the right instruction; extract baseJumpAddress. */
612     /* DEBUG */ parsing_printf( "%s[%d]: mov.ip located at 0x%lx\n", __FILE__, __LINE__, iter.current );
613     baseJumpAddress = iter.current & (~0x3);
614     foundMovFromIP = true;
615     break;
616   }
617         
618   int64_t maxTableLength = -1;
619   iter.setCurrentAddress( cmpltuUpperBound );
620   for( ; iter.hasPrev(); --iter ) {
621     instruction cmpltuInstruction = iter.getInstruction();
622                 
623     if( cmpltuInstruction.getUnitType() != instruction::I && cmpltuInstruction.getUnitType() != instruction::M ) { continue; }
624         
625     /* If so, is it a cmp.ltu? */
626     insn_tmpl cmpltu_tmpl = { cmpltuInstruction.getMachineCode() };
627     if( GET_OPCODE( &cmpltu_tmpl ) != 0xD 
628         || (!( cmpltu_tmpl.A8.x2 == 0x02 || cmpltu_tmpl.A8.x2 == 0x03 ))
629         || cmpltu_tmpl.A8.ta != 0x0 ) { continue; }
630         
631     /* Extract the immediate. */
632     maxTableLength = GET_A8_COUNT( &cmpltu_tmpl );
633     /* DEBUG */ parsing_printf( "%s[%d]: maxTableLength %d located at 0x%lx\n", __FILE__, __LINE__, maxTableLength, iter.current);
634     break;
635   }
636   if( maxTableLength <= 0 ) {
637     /* DEBUG */ parsing_printf( "%s[%d]: maxTableLength negative, aborting parse.\n", __FILE__, __LINE__ );
638     return false;
639   }
640         
641   /* DEBUG */ parsing_printf( "%s[%d]: parsed jump table (@ 0x%lx), base 0x%lx, %d entries\n", __FILE__, __LINE__, current,
642                               baseJumpAddress, maxTableLength);
643         
644   /* Extract the jump targets. */
645   for( unsigned int i = 0; i < maxTableLength; ++i ) {
646     uint64_t finalAddr = baseJumpAddress;
647                 
648     /* Get the jump table entry value. */
649     if( img ) {
650       /* The jump table may be in the code segment. */
651       void * ptr = img->getPtrToData( jumpTableAddress + (sizeof(uint64_t) * i) );
652       if( !ptr ) { ptr = img->getPtrToDataInText( jumpTableAddress + (sizeof(uint64_t) * i) ); }
653       if( !ptr ) {
654         /* DEBUG */ fprintf( stderr, "%s[%d]: unable to read jump target %d\n", __FILE__, __LINE__, i );
655         continue;
656       }
657       finalAddr += *((uint64_t *)ptr);
658     }
659     else {
660       void *ptr = instructions_->getPtrToInstruction( jumpTableAddress + (sizeof(uint64_t) * i) );
661       if( ! ptr ) {
662         /* DEBUG */ fprintf( stderr, "%s[%d]: unable to read jump target %d\n", __FILE__, __LINE__, i );
663         continue;
664       }
665       finalAddr += *((uint64_t *)ptr);
666     }
667         
668     if( ! foundMovFromIP ) { finalAddr += i * 8; }
669
670     /* DEBUG */ parsing_printf( "\t 0x%lx => 0x%lx\n", jumpTableAddress + (sizeof(uint64_t)*i), finalAddr );
671     targetAddresses.insert( finalAddr );
672   } /* end jump table iteration */
673     
674   /* DEBUG */ parsing_printf( "%s[%d]: located jump table for 0x%lx, at GP + 0x%lx %s\n\n", __FILE__, __LINE__, current, jumpTableOffset, foundInstruction2 ? "with double indirection." : "with single indirection." );
675   return true;
676 } /* end of getMultipleJumpTargets(). */
677
678
679 bool InstrucIter::delayInstructionSupported()
680 {
681   return false;
682 }
683
684 Address InstrucIter::peekPrev()
685 {
686   int instructionSlot = extractInstructionSlot( current ); 
687   switch( instructionSlot ) {
688   case 0: {
689     // This is complicated. If we're going onto a bundle
690     // with a long insn, skip 2.
691     Address temp = current - 16;
692     void *tmpPtr;
693     assert(instructions_);
694     assert(instructions_->isValidAddress(temp));
695     tmpPtr = instructions_->getPtrToInstruction(temp);
696     ia64_bundle_t *rawBundle = (ia64_bundle_t *)tmpPtr;
697     IA64_bundle tmpBundle = IA64_bundle(*rawBundle);
698         
699     if (tmpBundle.hasLongInstruction())
700       return current - 16 + 1;
701     else
702       return current - 16 + 2;
703   }
704   case 1: return current - 1;
705   case 2: 
706     if (bundle.hasLongInstruction()) {
707       return current - 2;
708     }
709     else
710       return current - 1;
711   default: return 0;
712   }
713 }
714
715 Address InstrucIter::peekNext()
716 {
717   int instructionSlot = extractInstructionSlot( current );
718   switch( instructionSlot ) {
719   case 0: return current + 1;
720   case 1: 
721     if (bundle.hasLongInstruction())
722       return current - 1 + 16;
723     else
724       return current + 1;
725   case 2: return current - 2 + 16;
726   default: return 0;
727   }
728 }
729
730 void InstrucIter::setCurrentAddress(Address addr)
731 {
732   assert( (current % 0x10) < 3 );
733   current = addr;
734   initializeInsn();
735 }
736
737 instruction InstrucIter::getInstruction()
738 {       
739   return insn;
740 }
741
742 // Suuuure...
743 bool InstrucIter::isStackFramePreamble(int &) {
744   return true;
745 }
746
747 void InstrucIter::initializeInsn() {
748   unsigned short slotno = current % 16;
749   Address aligned = current - slotno;
750   assert(instructions_);
751   assert(instructions_->isValidAddress(aligned));
752   instPtr = instructions_->getPtrToInstruction(aligned);
753   if (instPtr == NULL) return;
754     
755   ia64_bundle_t *rawBundle = (ia64_bundle_t *)instPtr;
756   bundle = IA64_bundle(*rawBundle);
757     
758   if (bundle.hasLongInstruction() && 
759       (slotno == 2)) {
760     cerr << "Attempt to grab the middle of a long instruction!" << endl;
761     assert(0);
762   }
763     
764   instruction *newInsn = bundle.getInstruction(slotno);
765     
766   insn = *newInsn;
767     
768   // Aaaand delete newInsn...
769   delete newInsn;
770 }
771
772 instruction *InstrucIter::getInsnPtr() {
773   unsigned short slotno = current % 16;
774   Address aligned = current - slotno;
775   assert(instructions_);
776   assert(instructions_->isValidAddress(aligned));
777   instPtr = instructions_->getPtrToInstruction(aligned);
778     
779
780   if (instPtr == NULL) return NULL;
781     
782   ia64_bundle_t *rawBundle = (ia64_bundle_t *)instPtr;
783   bundle = IA64_bundle(*rawBundle);
784     
785   if (bundle.hasLongInstruction() && 
786       (slotno == 2)) {
787     cerr << "Attempt to grab the middle of a long instruction!" << endl;
788     assert(0);
789   }
790     
791   instruction *newInsn = bundle.getInstruction(slotno);
792
793   return newInsn;
794 }
795                
796 bool InstrucIter::isADynamicCallInstruction()
797 {
798   assert(instPtr);
799   return insn.getType() == instruction::INDIRECT_CALL;
800 }
801
802 bool InstrucIter::isALeaveInstruction()
803 {
804   return false;
805 }
806
807 bool InstrucIter::isFrameSetup()
808 {
809   return false;
810 }
811
812 bool InstrucIter::isFramePush()
813 {
814   return false;
815 }
816
817 bool InstrucIter::isANopInstruction()
818 {
819    return false;
820 }
821
822 bool InstrucIter::isSyscall()
823 {
824   // not implemented
825   return false;
826 }
827