Allow jump tables to use add-with-carry as well as add.
[dyninst.git] / parseAPI / src / IA_powerDetails.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 #include "IA_powerDetails.h"
33 #include "Visitor.h"
34 #include "Register.h"
35 #include "Dereference.h"
36 #include "Immediate.h"
37 #include "BinaryFunction.h"
38 #include "debug_parse.h"
39 #include <deque>
40
41 using namespace Dyninst;
42 using namespace InstructionAPI;
43 using namespace Dyninst::InsnAdapter;
44 using namespace Dyninst::ParseAPI;
45
46
47 namespace Dyninst
48 {
49 namespace InsnAdapter
50 {
51 namespace detail
52 {
53     class TOCandOffsetExtractor : public Dyninst::InstructionAPI::Visitor
54     {
55         public:
56             TOCandOffsetExtractor(Address TOCvalue) : toc_contents(TOCvalue) {}
57             virtual ~TOCandOffsetExtractor() {}
58             virtual void visit(BinaryFunction* b) {
59                 Address arg1 = m_stack.front();
60                 m_stack.pop_front();
61                 Address arg2 = m_stack.front();
62                 m_stack.pop_front();
63                 if(b->isAdd()) {
64                     result = arg1 + arg2;
65                 } else if(b->isMultiply()) {
66                     result = arg1 * arg2;
67                 } else {
68                     assert(!"unexpected binary function!");
69                     result = 0;
70                 }
71                 parsing_printf("\tTOC visitor visiting binary function, result is 0x%lx\n",
72                                result);
73                 m_stack.push_front(result);
74             }
75             virtual void visit(Immediate* i) {
76                 Address tmp = i->eval().convert<Address>();
77                 result = tmp;
78                 parsing_printf("\tTOC visitor visiting immediate, result is 0x%lx\n",
79                                result);
80                 m_stack.push_front(tmp);
81             }
82             virtual void visit(RegisterAST* r) {
83                 if(r->getID() == toc_reg->getID()) {
84                     m_stack.push_front(toc_contents);
85                 } else {
86                     m_stack.push_front(0);
87                 }
88                 result = m_stack.front();
89                 parsing_printf("\tTOC visitor visiting register, result is 0x%lx\n",
90                                result);
91             }
92             virtual void visit(Dereference*) {}
93             void clear() {
94                 m_stack.clear();
95                 result = 0;
96             }
97             std::deque<Address> m_stack;
98             Address result;
99             Address toc_contents;
100             RegisterAST::Ptr toc_reg;
101     };
102 }
103 }
104 };
105
106
107 bool IA_powerDetails::findTableAddrNoTOC(const IA_IAPI* blockToCheck)
108 {
109     tableStartAddress = 0;
110     std::set<RegisterAST::Ptr> regs;
111     toc_visitor->clear();
112     while(patternIter != blockToCheck->allInsns.begin())
113     {
114         patternIter--;
115         if(patternIter == blockToCheck->allInsns.begin())
116         {
117             break;
118         }
119         parsing_printf("\tchecking insn %s at 0x%lx\n", patternIter->second->format().c_str(),
120                        patternIter->first);
121         if((patternIter->second->getOperation().getID() == power_op_addi) ||
122            (patternIter->second->getOperation().getID() == power_op_si))
123         {
124             regs.clear();
125             patternIter->second->getReadSet(regs);
126             if(regs.size() != 1) {
127                 continue;
128             }
129             parsing_printf("\tfound 0x%lx: %s, checking for addis previous\n",
130                            patternIter->first,
131                            patternIter->second->format().c_str());
132             toc_visitor->clear();
133             patternIter->second->getOperand(2).getValue()->apply(toc_visitor.get());
134             tableStartAddress = toc_visitor->result;
135             patternIter--;
136             if(patternIter->second &&
137                (patternIter->second->getOperation().getID() == power_op_addis) &&
138                patternIter->second->isWritten(*(regs.begin())))
139             {
140                 parsing_printf("\tfound 0x%lx: %s, setting tableStartAddress\n",
141                                patternIter->first,
142                                patternIter->second->format().c_str());
143                 toc_visitor->clear();
144                 patternIter->second->getOperand(2).getValue()->apply(toc_visitor.get());
145                 tableStartAddress += (toc_visitor->result * 0x10000) & 0xFFFF0000;
146                 parsing_printf("\ttableStartAddress = 0x%lx\n",
147                                tableStartAddress);
148                 break;
149             }
150             tableStartAddress = 0;
151         }
152         else if(patternIter->second->getOperation().getID() == power_op_addis)
153         {
154             regs.clear();
155             patternIter->second->getReadSet(regs);
156             if(regs.size() != 1) {
157                 continue;
158             }
159             parsing_printf("\tfound 0x%lx: %s, checking for addi previous\n",
160                            patternIter->first,
161                            patternIter->second->format().c_str());
162             toc_visitor->clear();
163             patternIter->second->getOperand(2).getValue()->apply(toc_visitor.get());
164             tableStartAddress = toc_visitor->result;
165             tableStartAddress *= 10000;
166             tableStartAddress &= 0xFFFF0000;
167             patternIter--;
168             if(patternIter->second &&
169                ((patternIter->second->getOperation().getID() == power_op_addi) ||
170                 (patternIter->second->getOperation().getID() == power_op_si)) &&
171                patternIter->second->isWritten(*(regs.begin())))
172             {
173                 parsing_printf("\tfound 0x%lx: %s, setting tableStartAddress\n",
174                                patternIter->first,
175                                patternIter->second->format().c_str());
176                 toc_visitor->clear();
177                 patternIter->second->getOperand(2).getValue()->apply(toc_visitor.get());
178                 tableStartAddress += toc_visitor->result;
179                 parsing_printf("\ttableStartAddress = 0x%lx\n", tableStartAddress);
180                 break;
181             }
182             tableStartAddress = 0;
183         }
184     }
185     // If we've found an addi/addis combination and it's a relative table, look for a mfspr/thunk combination that
186     // feeds that...
187     if(tableStartAddress && tableIsRelative)
188     {
189         parsing_printf("\ttableStartAddress non-zero, tableIsRelative true\n");
190         bool foundThunk = false;
191         bool foundMFSPR = false;
192         Address GOTaddress = 0;
193         while(patternIter != blockToCheck->allInsns.begin())
194         {
195             patternIter--;
196             if(patternIter->second->getOperation().getID() == power_op_mfspr &&
197                patternIter->second->isWritten(*(regs.begin())))
198             {
199                 foundMFSPR = true;
200                 break;
201             }
202         }
203         while(patternIter != blockToCheck->allInsns.begin())
204         {
205             patternIter--;
206             if(patternIter->second->getCategory() == c_CallInsn) // mid-block call, must be a thunk
207             {
208                 patternIter++;
209                 parsing_printf("\tfound thunk/mfspr combo, adjusting tableStartAddress by 0x%lx\n", patternIter->first);
210                 GOTaddress = tableStartAddress + patternIter->first;
211                 foundThunk = true;
212                 break;
213             }
214         }
215         if(foundThunk && foundMFSPR)
216         {
217             toc_visitor->toc_reg = *(regs.begin());
218             toc_reg = toc_visitor->toc_reg;
219             toc_visitor->toc_contents = GOTaddress;
220             tableStartAddress = 0;
221             patternIter = currentBlock->curInsnIter;
222             parsing_printf("\t calling parseRelativeTableIdiom with toc_reg %s\n", toc_visitor->toc_reg->format().c_str());
223             return parseRelativeTableIdiom();
224         }
225     }
226     else
227     {
228         parsing_printf("\ttableStartAddress = 0x%lx, tableIsRelative = %s\n", tableStartAddress,
229                 tableIsRelative ? "true" : "false");
230     }
231     return tableStartAddress == 0;
232 }
233
234 bool IA_powerDetails::parseRelativeTableIdiom()
235 {
236     while(patternIter != currentBlock->allInsns.begin())
237     {
238         patternIter--;
239         parsing_printf("\t checking 0x%lx: %s for lwz/ld\n", patternIter->first, patternIter->second->format().c_str());
240         if((patternIter->second->getOperation().getID() == power_op_lwz ||
241             patternIter->second->getOperation().getID() == power_op_ld) &&
242             patternIter->second->isRead(toc_reg))
243         {
244             toc_visitor->clear();
245             patternIter->second->getOperand(1).getValue()->apply(toc_visitor.get());
246             parsing_printf("%s[%d]: setting jumpStartAddress to 0x%lx, insn %s, TOC 0x%lx\n", FILE__, __LINE__,
247                            toc_visitor->result, patternIter->second->format().c_str(), toc_visitor->toc_contents);
248             jumpStartAddress = toc_visitor->result;
249             break;
250         }
251     }
252     if(patternIter == currentBlock->allInsns.begin())
253     {
254             // If we've already backed up to the beginning, we're not going to find a legit table
255             // start address; bail now.
256         parsing_printf("%s[%d]: jumpStartAddress insn was first in block w/relative table, ret false\n",
257                        FILE__, __LINE__);
258         return false;
259     }
260         // Anyone know what this does?
261     patternIter--;
262     if((patternIter->second->getOperation().getID() == power_op_lwz ||
263         patternIter->second->getOperation().getID() == power_op_ld))
264     {
265         toc_visitor->clear();
266         patternIter->second->getOperand(1).getValue()->apply(toc_visitor.get());
267         adjustEntry = toc_visitor->result;
268         foundAdjustEntry = true;
269         parsing_printf("%s[%d]: setting adjustEntry to 0x%lx, insn %s, TOC 0x%lx\n", FILE__, __LINE__,
270                        toc_visitor->result, patternIter->second->format().c_str(), toc_visitor->toc_contents);
271     }
272
273     while(patternIter != currentBlock->allInsns.begin()){
274         patternIter--;
275         if((patternIter->second->getOperation().getID() == power_op_lwz ||
276             patternIter->second->getOperation().getID() == power_op_ld) &&
277             patternIter->second->isRead(toc_reg))
278         {
279             toc_visitor->clear();
280             patternIter->second->getOperand(1).getValue()->apply(toc_visitor.get());
281             tableStartAddress = toc_visitor->result;
282             parsing_printf("%s[%d]: setting tableStartAddress to 0x%lx, insn %s, TOC 0x%lx\n", FILE__, __LINE__,
283                            toc_visitor->result, patternIter->second->format().c_str(), toc_visitor->toc_contents);
284             break;
285         }
286     }
287     return true;
288 }
289
290 // This should only be called on a known indirect branch...
291 bool IA_powerDetails::parseJumpTable(Block* currBlk,
292                              std::vector<std::pair< Address, EdgeTypeEnum> >& outEdges)
293 {
294     Address initialAddress = currentBlock->current;
295     toc_reg.reset(new RegisterAST(ppc32::r2));
296
297     TOC_address = currentBlock->_obj->cs()->getTOC();
298     toc_visitor.reset(new detail::TOCandOffsetExtractor(TOC_address));
299     toc_visitor->toc_reg = toc_reg;
300     
301     // If there are no prior instructions then we can't be looking at a
302     // jump through a jump table.
303     if(currentBlock->allInsns.size() < 2) {
304         parsing_printf("%s[%d]: allInsns.size() == %d, ret false", FILE__, __LINE__, currentBlock->allInsns.size());
305         return false;
306     }
307
308
309     // Check if the previous instruction is a move to CTR or LR;
310     // if it is, then this is the pattern we're familiar with.  The
311     // register being moved into CTR or LR has the address to jump to.
312     patternIter = currentBlock->curInsnIter;
313     patternIter--;
314     RegisterAST::Ptr jumpAddrReg;
315     static RegisterAST::Ptr linkReg(new RegisterAST(ppc32::lr));
316     static RegisterAST::Ptr countReg(new RegisterAST(ppc32::ctr));
317     std::set<RegisterAST::Ptr> regs;
318     if(patternIter->second->getOperation().getID() == power_op_mtspr &&
319        (patternIter->second->isWritten(linkReg) ||
320        patternIter->second->isWritten(countReg)))
321     {
322         regs.clear();
323         patternIter->second->getReadSet(regs);
324         if(regs.size() != 1) {
325             parsing_printf("expected mtspr to read 1 register, insn is %s\n", patternIter->second->format().c_str());
326             return false;
327         }
328         jumpAddrReg = *(regs.begin());
329     }
330     else
331     {
332         parsing_printf("%s[%d]: couldn't find mtspr at prev insn %s, ret false", FILE__, __LINE__,
333                        patternIter->second->format().c_str());
334         return false;
335     }
336     assert(jumpAddrReg);
337     // In the pattern we've seen, if the instruction previous to this is
338     // an add with a result that ends up being used as the jump address,
339     // then we're adding a relative value we got from the table to a base
340     // address to get the jump address; in other words, the contents of
341     // the jump table are relative.
342     tableIsRelative = false;
343     if(patternIter != currentBlock->allInsns.begin())
344     {
345         patternIter--;
346         if(patternIter->second->getOperation().getID() == power_op_add &&
347            patternIter->second->isWritten(*(regs.begin())))
348         {
349             tableIsRelative = true;
350         }
351     }
352
353     patternIter = currentBlock->curInsnIter;
354     
355     jumpStartAddress = 0;
356     adjustEntry = 0;
357     tableStartAddress = 0;
358     foundAdjustEntry = false;
359     
360
361     if(!TOC_address)
362     {
363         findTableAddrNoTOC(currentBlock);
364         jumpStartAddress = tableStartAddress;
365     }
366     else if (tableIsRelative) {
367         if(!parseRelativeTableIdiom())
368         {
369             return false;
370         }
371     } else {
372         foundAdjustEntry = false;
373         while( patternIter != currentBlock->allInsns.begin() )
374         {
375             if(patternIter->second->getOperation().getID() == power_op_addi &&
376                patternIter->second->isWritten(jumpAddrReg) &&
377                !foundAdjustEntry)
378             {
379                 foundAdjustEntry = true;
380                 toc_visitor->clear();
381                 patternIter->second->getOperand(1).getValue()->apply(toc_visitor.get());
382                 adjustEntry = toc_visitor->result;
383                 regs.clear();
384                 patternIter->second->getReadSet(regs);
385                 jumpAddrReg = *(regs.begin());
386                 assert(jumpAddrReg);
387             }
388             else if(patternIter->second->getOperation().getID() == power_op_lwz &&
389                     patternIter->second->isRead(toc_reg) &&
390                     patternIter->second->isWritten(jumpAddrReg))
391             {
392                 toc_visitor->clear();
393                 patternIter->second->getOperand(1).getValue()->apply(toc_visitor.get());
394                 tableStartAddress = toc_visitor->result;
395                 break;
396             }
397             patternIter--;
398         }
399     }
400     
401     Block::edgelist & sourceEdges = currBlk->sources();
402     if(sourceEdges.size() != 1 || (*sourceEdges.begin())->type() == CALL) {
403         parsing_printf("%s[%d]: jump table not properly guarded, ret false\n", FILE__, __LINE__);
404         return false;
405     }
406
407
408     
409     // We could also set this = jumpStartAddress...
410     if (tableStartAddress == 0)  {
411         if(!TOC_address)
412         {
413             Block* sourceBlock = (*sourceEdges.begin())->src();
414             Address blockStart = sourceBlock->start();
415             const unsigned char* b = (const unsigned char*)(currentBlock->_isrc->getPtrToInstruction(blockStart));
416             InstructionDecoder dec(b, sourceBlock->size(), currentBlock->_isrc->getArch());
417             IA_IAPI prevBlock(dec, blockStart,currentBlock->_obj,currentBlock->_cr,currentBlock->_isrc);
418             while(!prevBlock.hasCFT() && prevBlock.getInstruction()) {
419                 prevBlock.advance();
420             }
421
422             parsing_printf("%s[%d]: checking previous block for table addr\n", FILE__, __LINE__);
423             patternIter = prevBlock.curInsnIter;
424             findTableAddrNoTOC(&prevBlock);
425             if(!jumpStartAddress)
426             {
427                 jumpStartAddress = tableStartAddress;
428             }
429         }
430         if(tableStartAddress == 0)
431         {
432             parsing_printf("%s[%d]: couldn't find table start addr, ret false\n", FILE__, __LINE__);
433             return false;
434         }
435     }
436     
437     parsing_printf("%s[%d]: table start addr is 0x%x\n", FILE__, __LINE__, tableStartAddress);
438     int maxSwitch = 0;
439   
440     Block* sourceBlock = (*sourceEdges.begin())->src();
441     Address blockStart = sourceBlock->start();
442     const unsigned char* b = (const unsigned char*)(currentBlock->_isrc->getPtrToInstruction(blockStart));
443     InstructionDecoder dec(b, sourceBlock->size(), currentBlock->_isrc->getArch());
444     IA_IAPI prevBlock(dec, blockStart,currentBlock->_obj,currentBlock->_cr,currentBlock->_isrc);
445     while(!prevBlock.hasCFT() && prevBlock.getInstruction()) {
446         prevBlock.advance();
447     }
448
449     parsing_printf("%s[%d]: checking for max switch...\n", FILE__, __LINE__);
450     patternIter = prevBlock.curInsnIter;
451
452     while( patternIter != prevBlock.allInsns.begin() ) {
453         parsing_printf("\t\tchecking insn 0x%x: %s for cond branch\n", patternIter->first,
454                        patternIter->second->format().c_str());
455         if(patternIter->second->getOperation().getID() == power_op_bc) // make this a true cond. branch check
456         {
457             if(patternIter != prevBlock.allInsns.begin())
458             {
459                 patternIter--;
460                 parsing_printf("\t\tchecking insn 0x%x: %s for compare\n", patternIter->first,
461                                patternIter->second->format().c_str());
462                 if(patternIter->second->getOperation().getID() == power_op_cmpi ||
463                    patternIter->second->getOperation().getID() == power_op_cmpli)
464                 {
465                     maxSwitch = patternIter->second->getOperand(2).getValue()->eval().convert<int>() + 1;
466                     break;
467                 }
468             }
469             else
470             {
471                 parsing_printf("\t\t ******** prevBlock.allInsns begins with cond branch!\n");
472                 break;
473             }
474         }
475         if(patternIter != prevBlock.allInsns.begin())
476             patternIter--;
477     }
478
479     parsing_printf("%s[%d]: After checking: max switch %d\n", FILE__, __LINE__, maxSwitch);
480     if(!maxSwitch){
481         return false;
482     }
483
484     Address jumpStart = 0;
485     Address tableStart = 0;
486     bool is64 = (currentBlock->_isrc->getAddressWidth() == 8);
487
488     if(TOC_address)
489     {
490         if (tableIsRelative) {
491             void *jumpStartPtr = currentBlock->_isrc->getPtrToData(jumpStartAddress);
492             parsing_printf("%s[%d]: jumpStartPtr (0x%lx) = %p\n", FILE__, __LINE__, jumpStartAddress, jumpStartPtr);
493             if (jumpStartPtr)
494                 jumpStart = (is64
495                         ? *((Address  *)jumpStartPtr)
496                 : *((uint32_t *)jumpStartPtr));
497             parsing_printf("%s[%d]: jumpStart 0x%lx, initialAddr 0x%lx\n",
498                            FILE__, __LINE__, jumpStart, initialAddress);
499             if (jumpStartPtr == NULL) {
500                 return false;
501             }
502         }
503         void *tableStartPtr = currentBlock->_isrc->getPtrToData(tableStartAddress);
504         parsing_printf("%s[%d]: tableStartPtr (0x%lx) = %p\n", FILE__, __LINE__, tableStartAddress, tableStartPtr);
505         tableStart = *((Address *)tableStartPtr);
506         if (tableStartPtr)
507             tableStart = (is64
508                     ? *((Address  *)tableStartPtr)
509             : *((uint32_t *)tableStartPtr));
510         else {
511             return false;
512         }
513         parsing_printf("\t... tableStart 0x%lx\n", tableStart);
514
515         bool tableData = false;
516
517         for(int i=0;i<maxSwitch;i++){
518             Address tableEntry = adjustEntry + tableStart + (i * 4 /*instruction::size()*/);
519             parsing_printf("\t\tTable entry at 0x%lx\n", tableEntry);
520             if (currentBlock->_isrc->isValidAddress(tableEntry)) {
521                 int jumpOffset;
522                 if (tableData) {
523                     jumpOffset = *((int *)currentBlock->_isrc->getPtrToData(tableEntry));
524                 }
525                 else {
526                     jumpOffset = *((int *)currentBlock->_isrc->getPtrToInstruction(tableEntry));
527                 }
528
529                 parsing_printf("\t\t\tjumpOffset 0x%lx\n", jumpOffset);
530                 Address res = (Address)(jumpStart + jumpOffset);
531
532                 if (currentBlock->_isrc->isCode(res)) {
533                     outEdges.push_back(std::make_pair((Address)(jumpStart+jumpOffset), INDIRECT));
534                     parsing_printf("\t\t\tEntry of 0x%lx\n", (Address)(jumpStart + jumpOffset));
535                 }
536             }
537             else {
538                 parsing_printf("\t\tAddress not valid!\n");
539             }
540         }
541     }
542 // No TOC, so we're on Power32 Linux.  Do the ELF thing.
543     else
544     {
545         jumpStart = jumpStartAddress;
546         tableStart = tableStartAddress;
547         if(toc_visitor->toc_contents)
548         {
549             void* tmp = NULL;
550             if(currentBlock->_isrc->isValidAddress(jumpStartAddress))
551             {
552                 tmp = currentBlock->_isrc->getPtrToData(jumpStartAddress);
553                 if(!tmp)
554                 {
555                     tmp = currentBlock->_isrc->getPtrToInstruction(jumpStartAddress);
556                 }
557                 if(tmp)
558                 {
559                     jumpStart = *((Address*)tmp);
560                     parsing_printf("\t\tjumpStart adjusted to 0x%lx\n", jumpStart);
561                 }
562             }
563             if(currentBlock->_isrc->isValidAddress(tableStartAddress))
564             {
565                 tmp = currentBlock->_isrc->getPtrToData(tableStartAddress);
566                 if(!tmp)
567                 {
568                     tmp = currentBlock->_isrc->getPtrToInstruction(tableStartAddress);
569                 }
570                 if(tmp)
571                 {
572                     tableStart = *((Address*)tmp);
573                     parsing_printf("\t\ttableStart adjusted to 0x%lx\n", jumpStart);
574                 }
575             }
576         }
577         int entriesAdded = 0;
578         for(int i = 0; i < maxSwitch; i++)
579         {
580             void* ptr = NULL;
581             Address tableEntry = tableStart + i*4; // instruction::size();
582             if(currentBlock->_isrc->isValidAddress(tableEntry))
583             {
584                 ptr = currentBlock->_isrc->getPtrToInstruction(tableEntry);
585             }
586             if(ptr)
587             {
588                 int jumpOffset = *((int *)ptr);
589                 outEdges.push_back(std::make_pair((Address)(jumpStart+jumpOffset), INDIRECT));
590                 parsing_printf("\t\t\t[0x%lx] -> 0x%lx (0x%lx in table)\n", tableEntry,
591                                jumpStart+jumpOffset,
592                                 jumpOffset);
593                 ++entriesAdded;
594             }
595             else
596             {
597                 parsing_printf("\t\t\t[0x%lx] -> [INVALID]\n", tableEntry);
598             }
599         }
600         if(!entriesAdded)
601         {
602             parsing_printf("%s[%d]: no entries added from jump table, returning false\n", FILE__, __LINE__);
603             return false;
604         }
605         parsing_printf("%s[%d]: Found %d entries in jump table, returning success\n", FILE__, __LINE__, entriesAdded);
606     }
607
608 // Sanity check entries in res
609     for (std::vector<std::pair<Address, EdgeTypeEnum> >::iterator iter = outEdges.begin();
610          iter != outEdges.end(); iter++) {
611              if ((iter->first) % 4) {
612                  parsing_printf("Warning: found unaligned jump table destination 0x%lx for jump at 0x%lx, disregarding table\n",
613                                 iter->first, initialAddress);
614                  return false;
615              }
616          }
617          return true;
618 }