IDA C++ SDK 9.2
Loading...
Searching...
No Matches
jumptable.hpp
Go to the documentation of this file.
1/*
2 * Interactive disassembler (IDA).
3 * Copyright (c) 1990-2025 Hex-Rays
4 * ALL RIGHTS RESERVED.
5 *
6 */
7
8#ifndef __JUMPTABLE_HPP
9#define __JUMPTABLE_HPP
10
11#include <pro.h>
12#include <ua.hpp> // op_t
13#include <nalt.hpp> // switch_info_t, jumptable_info_t
14
15// Class to check for a jump table sequence.
16// This class should be used in preference to the hard encoding of jump table sequences
17// because it allows for:
18// - instruction rescheduling
19// - intermingling the jump sequence with other instructions
20// - sequence variants
21//
22// For this class:
23// all instructions of the sequence are numbered starting from the last instruction.
24// The last instruction has the number 0.
25// The instruction before the last instruciton has the number 1, etc.
26// There is a virtual function jpiN() for each instruction of the sequence
27// These functions return true if 'insn' is filled with the required instruction
28//
29// The comparison is made in the match() function:
30//
31// ea points to the last instruction of the sequence (instruction #0)
32//
33// the 'depends' array contains dependencies between the instructions of the sequence.
34// For example:
35// ARM thumb LDRH switch
36// 7 SUB Ra, #minv (optional)
37// 6 CMP Ra, #size
38// 5 BCS defea
39// 4 ADR Rb, jt
40// 3 ADD Rb, Rb, Ra
41// 2 LDRH Rb, [Rb,Ra]
42// 1 LSL Rb, Rb, #1
43// 0 ADD PC, Rb
44// In this sequence, instruction #0 depends on the value of Rb which is produced
45// by the instruction #1. So, the instruction #0 depends on #1. Therefore, depends[0]
46// will contain '1' as its element.
47// The instruction #3 depends on 2 registers: Ra and Rb, or in other words,
48// it depends on the instructions #4 and #6. Therefore, depends[2] will contain { 4, 6 }
49// Maximum 4 dependencies per instruction are allowed.
50//
51// FIXME
52// The 'roots' array contains the first instruction of the dependency chains.
53// In our case we can say that there are 2 dependency chains:
54// 0 -> 1 -> 2 -> 3 -> 4
55// -> 6 -> 7
56// 5 -> 6
57// Therefore the roots array will consist of {1, 5}.
58// 0 denotes the end of the chain and cannot be the root of a dependency chain
59// Usually 1 is a root of any jump sequence.
60//
61// The dependency array allows for checking for optimized sequences of instructions.
62// If 2 instructions are not dependent on each other, they may appear in any order.
63// (for example, the instruction #4 and the instruction sequence #5-6-7 may appear
64// in any order because they do not depend on each other)
65// Also any other instructions not modifying the register values may appear between
66// the instructions of the sequence (due to the instruction rescheduling performed
67// by the compiler).
68//
69// Provision for optional instructions:
70// The presence of an optional instruction in the sequence (like #7) is signalled
71// by a negative number of the dependency in the 'depends' array.
72//
73// Provision for variable instructions:
74// In some cases several variants of the same instructions may be supported.
75// For example, the instruction #5 might be BCS as well as BGE. It is the job of
76// the jpi5() function to check for all variants.
77//
78// In order to use the 'jump_pattern_t' class you should derive another class from it
79// and define the jpiN() virtual functions.
80// Then you have to define the 'depends' and 'roots' arrays and call the match()
81// function.
82// If you processor contains instructions who modify registers in peculiar ways
83// you might want to override the check_spoiled() function.
84
85
86//----------------------------------------------------------------------
87// Macro to declare implementation of methods of jump_pattern_t
88class jump_pattern_t;
89// tracked registers
90// We use the 'size' term to denote the number of bits involved in the insn.
91// E.g. an operand of type dt_byte has 8-bit size.
92// We store the current size (the number of used bits) in the DTYPE field
93// of the 'op_t' structure. It may differ from the size of operand in the
94// insn. See the comment for set_moved().
95// We extend the 'op_dtype_t' type by some negative constants to denote
96// sizes from 2 to 7 bits.
98#define DECLARE_JUMP_PATTERN_HELPERS(decl)\
99decl void ida_export check_spoiled_jpt(const jump_pattern_t *_this, tracked_regs_t *_regs); \
100decl bool ida_export match_jpt(jump_pattern_t *_this);\
101decl bool ida_export same_value_jpt(jump_pattern_t *_this, const op_t &op, int r_i);\
102decl bool ida_export track_value_until_address_jpt(jump_pattern_t *_this, op_t *op, ea_t ea);\
103decl void ida_export combine_regs_jpt(jump_pattern_t *_this, tracked_regs_t *dst, const tracked_regs_t &src, ea_t ea);\
104decl void ida_export mark_switch_insns_jpt(const jump_pattern_t *_this, int last, int);\
105decl bool ida_export set_moved_jpt(const jump_pattern_t *_this, const op_t &dst, const op_t &src, tracked_regs_t &_regs, op_dtype_t real_dst_dtype, op_dtype_t real_src_dtype);
106
108
109class jump_pattern_t
110{
111protected:
112 // 32-bit operand generates a 32-bit result, zero- or sign-extended to a
113 // 64-bit result. This flag may be overwritten in processor modules.
114 // For example:
115 // ARM: MOV W8, #0x3C will clear the upper 32 bits of X8,
116 // PC : mov eax, 3Ch will clear the upper 32 bits of rax
117 bool modifying_r32_spoils_r64;
118
119public:
120 typedef bool (jump_pattern_t::*check_insn_t)(void);
121 inline jump_pattern_t(
122 switch_info_t *si, // may be nullptr
123 const char (*depends)[4],
124 int last_reg);
125
126 insn_t insn; // current instruction
127 switch_info_t *si; // answers will be here
128
129 enum
130 {
131 NINS = 16, // the maximum length of the sequence
132 INS_MASK = 0x0F,
133 };
134 ea_t eas[NINS];
135 bool skip[NINS]; // do not check the Nth insn if skip[N] is true
136 int non_spoiled_reg; // if non_spoiled_reg was spoiled then we stop
137 // matching
138 check_insn_t check[NINS];
139 // this is the hidden return value of the jpiN() methods. If it is set and
140 // jpiN() returned 'true' then we stop processing the dependency chain. If
141 // it is set and jpiN() returned 'false' then we stop checking the insns
142 // in the current basic block and we are switching to the next one (and we
143 // fail if there is no such block).
144 bool stop_matching;
145 // this flag can be analyzed by jpiN(). It means that the current insn is
146 // in the linear flow from the previous insn. It is always 'true' if the
147 // insn has JPT_NEAR flag.
148 bool in_linear_flow;
149 // this address can be analyzed by jpiN(). It means the end of the current
150 // block. It may help if we want to check in-block jumps.
151 ea_t block_end;
152
153 #define JPT_OPT 0x10 // the dependent insn might be missing
154 #define JPT_NEAR 0x20 // the dependent insn must be in the linear flow
155
156 const char (*depends)[4]; // instruction, on which we depend, and
157 // additional JPT_... flags
158
159 // mark swith instructions to be ignored by the decompiler
160 // do not mark the indirect jmp (eas[0]) as ignored
161 // it will be used to recognize switch idioms
162 // unmark NLOWCASE insns after LAST (in the case of SWI_HXNOLOWCASE flag)
163 void mark_switch_insns(int last = NINS - 1, int nlowcase = 0) const
164 {
165 mark_switch_insns_jpt(this, last, nlowcase);
166 }
167
168 // for fragmented switch idioms, cmp/jbe might be located in a separate
169 // fragment. we must not mark these instructions as part of the switch
170 // idiom because doing so would spoil the program logic for the decompiler
171 // and make the switch operator unreachable. the following vector keeps
172 // addresses of all instructions which must not be marked. this vector is
173 // maintained by derived classes.
174 eavec_t remote_code;
175 // extra insns used to calculate values (discovered by find_op_value)
176 eavec_t extra_insn_eas;
177 // tracked registers
178 tracked_regs_t regs;
179
180 // handle a possible delay slot situation
181 // while walking backwards in the execution flow
182 // if <branch> is false and <ea> is in a delay
183 // slot of a branch likely instruction
184 // then set <ea> to the branch instruction
185 // (=annul the delay slot)
186 // if <branch> is true and the instruction at <ea>
187 // has a delay slot then set <ea> to the delay slot
188 // (=execute the delay slot)
189 virtual void process_delay_slot(ea_t &/*ea*/, bool /*branch*/) const {}
190
191 enum
192 {
193 // an artificial operand type to track the address of the conditional jump
194 // .addr - address of the conditional jump
195 // .specval - address of the default case
196 // .specflag1 - the conditional jump flags (see below cc_*)
197 // the derived class can use .reg to track the condition register
198 o_condjump = 99,
199 cc_inc_ncases = 0x01, // increment ncases
200 cc_check_max_ncases = 0x02, // comparison with the maximum value
201
202 // an artificial operand type to count something
203 // .value - the counter
204 o_count = 100,
205 };
206
207 // compare supported operands
208 virtual bool equal_ops(const op_t &x, const op_t &y) const
209 {
210 if ( x.type != y.type )
211 return false;
212 switch ( x.type )
213 {
214 case o_void:
215 // consider spoiled values as not equal
216 return false;
217 case o_reg:
218 // ignore difference in the data size of registers
219 return x.reg == y.reg;
220 case o_count:
221 return x.value == y.value;
222 case o_condjump:
223 // we do not track the condition flags
224 return true;
225 }
226 return false;
227 }
228
229 // return true if the instruction `insn' is a move one,
230 // there is no need check spoiled registers in this case
231 virtual bool handle_mov(tracked_regs_t & /*_regs*/ )
232 {
233 return false;
234 }
235 // does the instruction `insn' spoil `_regs' ?
236 virtual void check_spoiled(tracked_regs_t *_regs) const
237 {
238 check_spoiled_jpt(this, _regs);
239 }
240 // some binaries use the following pattern
241 // xor eax, eax | mov al, cl
242 // so we can extend dtype of the operand from dt_byte to dt_dword
243 virtual op_dtype_t extend_dtype(const op_t &op) const
244 {
245 return op.dtype; // do not extend
246 }
247
248 // these methods are not virtual and should be used in processor
249 // module only
250 inline void track(int reg, int r_i, op_dtype_t dtype);
251 inline void trackop(const op_t &op, int r_i);
252 inline bool is_spoiled(int r_i) { return regs[r_i].type == o_void; }
253 inline bool is_equal(int reg, int r_i, op_dtype_t dtype);
254 inline bool is_equal(const op_t &op, int r_i);
255 inline bool same_value(const op_t &op, int r_i);
256 inline bool track_value_until_address(op_t *op, ea_t ea);
257
258 virtual bool jpi0(void) = 0;
259 virtual bool jpi1(void) { return false; }
260 virtual bool jpi2(void) { return false; }
261 virtual bool jpi3(void) { return false; }
262 virtual bool jpi4(void) { return false; }
263 virtual bool jpi5(void) { return false; }
264 virtual bool jpi6(void) { return false; }
265 virtual bool jpi7(void) { return false; }
266 virtual bool jpi8(void) { return false; }
267 virtual bool jpi9(void) { return false; }
268 virtual bool jpia(void) { return false; }
269 virtual bool jpib(void) { return false; }
270 virtual bool jpic(void) { return false; }
271 virtual bool jpid(void) { return false; }
272 virtual bool jpie(void) { return false; }
273 virtual bool jpif(void) { return false; }
274 // jpi<n> will be called if pre_jpi returns true
275 virtual bool pre_jpi(int /*n*/) { return true; }
276
277 bool match(const insn_t &_insn) { insn = _insn; return match_jpt(this); }
278
279 // remove compiler warnings -- class with virtual functions MUST have virtual destructor
280 virtual ~jump_pattern_t() {}
281
282 // helpers for mov instruction tracing (see methods handle_mov(),
283 // check_spoiled() above)
284 inline static void set_spoiled(tracked_regs_t *_regs);
285 inline void set_spoiled(tracked_regs_t *_regs, const op_t &op) const;
286 // track 'mov' insn: dst <- src
287 // it returns 'true' if insn changes any of the tracked registers
288 // REAL_DST_DTYPE is the size that will be changed in the DST operand by
289 // the insn. It can be greater than the operand size because some insns
290 // clear the upper bits. For example:
291 // xor eax, eax | mov ax, cx REAL_DST_DTYPE is 32
292 // xor bh, bh | mov bl, cl REAL_DST_DTYPE is 16
293 // Extending of the 32-bit register to 64 bits is performed automatically
294 // based on the modifying_r32_spoils_r64 flag.
295 // REAL_SRC_DTYPE is the size that will be used in the SRC operand by the
296 // insn. It can be less than the operand size. For example:
297 // ARM: AND W8, W8, #0xFF will use 8 bits of X8,
298 // PC : cwde will use 16 bits of rax.
299 bool set_moved(
300 const op_t &dst,
301 const op_t &src,
302 tracked_regs_t &_regs,
303 op_dtype_t real_dst_dtype = dt_void,
304 op_dtype_t real_src_dtype = dt_void) const
305 {
306 return set_moved_jpt(this, dst, src, _regs, real_dst_dtype, real_src_dtype);
307 }
308 // calculate state of registers before a conditional jump <ea> as the
309 // combination of states of each branch
310 void combine_regs(
311 tracked_regs_t *dst,
312 const tracked_regs_t &src,
313 ea_t ea)
314 {
315 combine_regs_jpt(this, dst, src, ea);
316 }
317
318protected:
319 bool match_tree();
320 bool follow_tree(ea_t ea, int n);
321 bool same_value_impl(const op_t &op, int r_i);
322 bool track_value_until_address_impl(op_t *op, ea_t ea);
323
324 inline bool equal_ops_dtype(const op_t &op, const op_t &reg) const;
325 static inline bool is_narrower(op_dtype_t dt1, op_dtype_t dt2);
326 enum
327 {
328 dt_7bit = 255,
329 dt_6bit = 254,
330 dt_5bit = 253,
331 dt_4bit = 252,
332 dt_3bit = 251,
333 dt_2bit = 250,
334 };
335 static inline int get_dtype_nbits(op_dtype_t dtype);
336
337 // helper for check_spoiled()
338 // TODO introduce new virtual methods spoils() and spoils_flags() and
339 // replace check_spoiled() by non-virtual method
340 inline void check_spoiled_not_reg(
341 tracked_regs_t *_regs,
342 uint maxop = UA_MAXOP) const;
343
345};
346
347//----------------------------------------------------------------------
348// kinds of jump tables
349enum { JT_NONE = 0, JT_SWITCH, JT_CALL };
350// It returns a nonzero JT_... kind if it found a jump pattern. This kind is
351// passed to the check_table() function.
352typedef int is_pattern_t(switch_info_t *si, const insn_t &insn, procmod_t *procmod);
353// It returns a refined kind. For example, JT_NONE if the found jump pattern
354// is not a switch, or JT_CALL if it is a call of a func from an array
355typedef int table_checker_t(
356 switch_info_t *si,
357 ea_t jump_ea,
358 int is_pattern_res,
359 procmod_t *pm);
360// check a flat 32/16/8 bit jump table -- the most common case
361idaman int ida_export check_flat_jump_table(
362 switch_info_t *si,
363 ea_t jump_ea,
364 int is_pattern_res = JT_SWITCH);
365
366// This function finds a switch. It calls functions from the PATTERNS
367// array in turn until the first one returns a nonzero value.
368// If a suitable pattern is found, it calls check_table() for the final
369// check, passing a nonzero result code of the 'is_pattern_t' function.
370// If the CHECK_TABLE parameter is nullptr then check_flat_jump_table() is
371// called.
372// NAME is used for a debug output.
373// It returns 'false' if INSN is not a switch or it is a call of a func from
374// an array. In the latter case it defines this array.
375idaman bool ida_export check_for_table_jump(
376 switch_info_t *si,
377 const insn_t &insn,
378 is_pattern_t *const patterns[],
379 size_t qty,
380 table_checker_t *check_table = nullptr,
381 const char *name = nullptr);
382
383//----------------------------------------------------------------------
384// sometimes the size of the jump table is misdetected
385// check if any of the would-be targets point into the table
386// and if so, truncate it
387// if 'ignore_refs' is false, also stop at first data reference
388idaman void ida_export trim_jtable(
389 switch_info_t *si,
390 ea_t jump_ea,
391 bool ignore_refs = false);
392
393//----------------------------------------------------------------------
394// this function find the size of the jump table for indirect switches
395// (indirect switches have the values table which contains indexes into
396// the jump table)
397// in: si->ncases has the size of the values table
398// out: si->jcases is initialized
399idaman bool ida_export find_jtable_size(switch_info_t *si);
400
401//----------------------------------------------------------------------
402// get default jump address from the jump table.
403// This method can be used only for a sparse nonindirect switch with default
404// case in the jump table.
406 ea_t jump_ea,
407 const switch_info_t &si);
408
409//----------------------------------------------------------------------
410// get the specified target from the jump table.
411idaman ea_t ida_export get_jtable_target(
412 ea_t jump_ea,
413 const switch_info_t &si,
414 int i);
415
416
417//----------------------------------------------------------------------
418// iterate instructions in the backward execution flow
419//lint -esym(1512,backward_flow_iterator_t*) destructor is not virtual
420template<class State,class Ctrl>
421// State: default constructor, operator=
422// Ctrl: combine_regs(State *, const State& ,ea_t)
423// process_delay_slot(ea_t &/*ea*/, bool /*branch*/)
425{
426public:
427 ea_t cur_ea; // current address
428 State &regs; // current state of the tracked registers
429 Ctrl &ctrl; // to combine state
430 bool only_near; // should we follow only the linear flow?
432
433protected:
434 //lint --e{958} padding is required
435 func_t *pfn; // to check bounds
438 ea_t cur_end; // end of current basic block
440 // visited basic blocks:
441 // key_type - start of the block, mapped_type - end of the block;
442 typedef std::map<ea_t, ea_t> visited_t;
444 // waiting basic blocks:
445 // key_type - end of the block, mapped_type - state at the end;
446 struct state_t
447 {
448 State regs;
450 state_t() : regs(), insn_cnt(UINT_MAX) {}
451 };
452 typedef std::map<ea_t, state_t> waiting_t;
454
455public:
457 ea_t start_ea_,
458 State &start_regs,
459 Ctrl &ctrl_,
460 bool only_near_,
461 uint max_insn_cnt_ = 0)
462 : cur_ea(start_ea_),
463 regs(start_regs),
464 ctrl(ctrl_),
465 only_near(only_near_),
466 max_insn_cnt(max_insn_cnt_),
467 pfn(nullptr),
468 seg(nullptr),
469 start_ea(start_ea_),
470 cur_end(BADADDR),
471 insn_cnt(0),
472 visited(),
473 waiting()
474 {
475 // to check bounds
477 if ( pfn == nullptr )
478 {
480 QASSERT(10183, seg != nullptr);
481 }
482 }
483
484 // fl_U : no previous instruction (start of a function or a cycle,
485 // or non linear flow if ONLY_NEAR is true),
486 // fl_F : got previous instruction by linear flow,
487 // fl_JF: got previous instruction by jump;
489 // stop iterating the current basic block, switch to the lowest waiting
490 // block
492
493 inline ea_t get_cur_end() const
494 {
495 return cur_end == BADADDR ? cur_ea : cur_end;
496 }
497
498protected:
499 // find visited basic block containing the address
500 // it returns the pointer to the address of the block end or nullptr
501 inline ea_t *find_visited(ea_t ea);
502 // get the lowest to start_ea waiting block
504 // combine insn counter - count the shortest path
505 static inline void combine_insn_cnt(uint *dst, uint src)
506 {
507 if ( src < *dst )
508 *dst = src;
509 }
510
511 bool check_bounds() const
512 {
513 if ( pfn != nullptr )
514 return func_contains(pfn, cur_ea);
515 return seg->contains(cur_ea);
516 }
517};
518
519//-------------------------------------------------------------------------
520// simple backward flow iterator
521struct no_regs_t {};
523 : public backward_flow_iterator_t<no_regs_t, simple_bfi_t>
524{
526
527protected:
529
530public:
532 : base_t(ea, regs_, *this, false) {}
533 static void combine_regs(no_regs_t *, const no_regs_t &, ea_t) {}
534 static void process_delay_slot(ea_t &, bool) {}
535};
536
537
538//======================================================================
539// inline implementation
540//----------------------------------------------------------------------
541
542inline jump_pattern_t::jump_pattern_t(
543 switch_info_t *_si,
544 const char (*_depends)[4],
545 int last_reg)
546 : modifying_r32_spoils_r64(true),
547 si(_si),
548 non_spoiled_reg(-1),
549 in_linear_flow(false),
550 depends(_depends),
551 regs()
552{
553 if ( si != nullptr )
554 si->clear();
555 regs.resize(last_reg + 1);
556}
557
558//----------------------------------------------------------------------
559inline bool jump_pattern_t::equal_ops_dtype(
560 const op_t &op,
561 const op_t &reg) const
562{
563 if ( !equal_ops(op, reg) )
564 return false;
565 // operand should be wider than a tracked register
566 // e.g. after 'cmp cl, imm' we cannot use cx
567 if ( !is_narrower(op.dtype, reg.dtype) )
568 return true;
569 // we believe that dword is widened to qword
570 if ( modifying_r32_spoils_r64 && op.dtype == dt_dword )
571 return true;
572 // try to extend
573 if ( !is_narrower(extend_dtype(op), reg.dtype) )
574 return true;
575 return false;
576}
577
578//----------------------------------------------------------------------
579// return true if size1 is narrow than size2
580inline bool jump_pattern_t::is_narrower(op_dtype_t dt1, op_dtype_t dt2)
581{
582 if ( dt1 < dt_2bit )
583 return dt2 < dt_2bit && dt1 < dt2;
584 else
585 return dt2 < dt_2bit || dt1 < dt2;
586}
587
588//----------------------------------------------------------------------
589inline int jump_pattern_t::get_dtype_nbits(op_dtype_t dtype)
590{
591 switch ( dtype )
592 {
593 case dt_byte: return 8;
594 case dt_word: return 16;
595 case dt_dword: return 32;
596 case dt_qword: return 64;
597 case dt_7bit: return 7;
598 case dt_6bit: return 6;
599 case dt_5bit: return 5;
600 case dt_4bit: return 4;
601 case dt_3bit: return 3;
602 case dt_2bit: return 2;
603 default: return -1;
604 }
605}
606
607//----------------------------------------------------------------------
608inline void jump_pattern_t::check_spoiled_not_reg(
609 tracked_regs_t *_regs,
610 uint maxop) const
611{
612 uint32 feature = insn.get_canon_feature(PH);
613 if ( feature == 0 )
614 return;
615 for ( uint i = 0; i < maxop; ++i )
616 {
617 if ( has_cf_chg(feature, i)
618 && insn.ops[i].type != o_void
619 && insn.ops[i].type != o_reg )
620 {
621 set_spoiled(_regs, insn.ops[i]);
622 }
623 }
624}
625
626//----------------------------------------------------------------------
627inline void jump_pattern_t::track(int reg, int r_i, op_dtype_t dtype)
628{
629 regs[r_i].type = o_reg;
630 regs[r_i].reg = reg;
631 regs[r_i].dtype = dtype;
632}
633inline void jump_pattern_t::trackop(const op_t &op, int r_i)
634{
635 regs[r_i] = op;
636}
637
638//----------------------------------------------------------------------
639inline bool jump_pattern_t::is_equal(int reg, int r_i, op_dtype_t dtype)
640{
641 op_t op;
642 op.type = o_reg;
643 op.reg = reg;
644 op.dtype = dtype;
645 return is_equal(op, r_i);
646}
647inline bool jump_pattern_t::is_equal(const op_t &op, int r_i)
648{
649 if ( regs[r_i].type == o_void )
650 {
651 // there is no reason to continue match
652 stop_matching = true;
653 return false;
654 }
655 return equal_ops_dtype(op, regs[r_i]);
656}
657
658//----------------------------------------------------------------------
659inline bool jump_pattern_t::same_value(const op_t &op, int r_i)
660{
661 return same_value_jpt(this, op, r_i);
662}
663
664//----------------------------------------------------------------------
665inline bool jump_pattern_t::track_value_until_address(op_t *op, ea_t ea)
666{
667 return track_value_until_address_jpt(this, op, ea);
668}
669
670//----------------------------------------------------------------------
671inline void jump_pattern_t::set_spoiled(tracked_regs_t *__regs)
672{
673 tracked_regs_t &_regs = *__regs;
674 // spoil all registers
675 for ( size_t i = 0; i < _regs.size(); ++i )
676 _regs[i].type = o_void;
677}
678inline void jump_pattern_t::set_spoiled(tracked_regs_t *__regs, const op_t &op) const
679{
680 tracked_regs_t &_regs = *__regs;
681 for ( size_t i = 0; i < _regs.size(); ++i )
682 if ( equal_ops(_regs[i], op) )
683 _regs[i].type = o_void; // spoil register
684}
685
686//----------------------------------------------------------------------
687// find the previous instruction in code flow
688// take into account branches and potential delay slots
689template<class State,class Ctrl>
691{
692 size_t refcnt = 0;
693 // check visited basic block
694 ea_t *visited_end = find_visited(cur_ea);
695 if ( visited_end == nullptr )
696 {
697 // analyze references to the current address
699 if ( is_flow(F32) )
700 ++refcnt;
701 if ( has_xref(F32) && !is_func(F32) ) // do not count jumps to function
702 {
703 xrefblk_t xb;
704 for ( bool ok = xb.first_to(cur_ea, XREF_NOFLOW|XREF_CODE);
705 ok;
706 ok = xb.next_to() )
707 {
708 // count only xrefs from jumps
709 if ( xb.type == fl_JF || xb.type == fl_JN )
710 {
711 if ( only_near )
712 {
713 if ( refcnt > 0 )
714 return fl_U;
715 // do not consider the flow through another switch as linear
716 if ( (get_flags32(xb.from) & FF_JUMP) != 0 )
717 return fl_U;
718 }
719 ++refcnt;
720 ea_t ea = xb.from;
721 ctrl.process_delay_slot(ea, true);
722 // ignore jumps from already visited blocks
723 if ( find_visited(ea) != nullptr )
724 continue;
725 // add basic block to the waiting set (combine state of the
726 // tracked registers at the jump source)
727 state_t &src_state = waiting[ea];
728 ctrl.combine_regs(&src_state.regs, regs, ea);
730 }
731 }
732 }
733
734 if ( cur_end == BADADDR )
735 cur_end = cur_ea;
736
737 // try ordinary flow
738 if ( is_flow(F32) )
739 {
740 ea_t prev_ea = prev_not_tail(cur_ea);
741 if ( prev_ea != BADADDR )
742 {
743 cur_ea = prev_ea;
744 if ( check_bounds()
745 && (max_insn_cnt == 0 || insn_cnt < max_insn_cnt) )
746 {
747 ++insn_cnt;
748 // remove reached waiting basic block
749 typename waiting_t::iterator w = waiting.find(cur_ea);
750 if ( w != waiting.end() )
751 {
752 ctrl.combine_regs(&regs, w->second.regs, cur_ea);
753 combine_insn_cnt(&insn_cnt, w->second.insn_cnt);
754 waiting.erase(w);
755 }
756 else
757 {
758 ctrl.process_delay_slot(cur_ea, false);
759 }
760 return fl_F;
761 }
762 }
763 // choose another branch
764 }
765
766 // save block [cur_ea, cur_end] as visited
768 }
769 else if ( cur_end != BADADDR )
770 {
771 // reach visited basic block => extend it
772 *visited_end = cur_end;
773 }
774
775 // get the lowest waiting block
776 cref_t ret = get_waiting();
777 // consider one xref as a linear flow
778 if ( ret == fl_JF && refcnt == 1 && waiting.empty() )
779 ret = fl_F;
780 return ret;
781}
782
783//----------------------------------------------------------------------
784template<class State,class Ctrl>
786{
787 // check visited basic block
788 ea_t *visited_end = find_visited(cur_ea);
789 if ( visited_end == nullptr )
790 {
791 if ( cur_end == BADADDR )
792 cur_end = cur_ea;
793 // save block [cur_ea, cur_end] as visited
795 }
796 else if ( cur_end != BADADDR )
797 {
798 // reach visited basic block => extend it
799 *visited_end = cur_end;
800 }
801
802 // get the lowest waiting block
803 return get_waiting();
804}
805
806//----------------------------------------------------------------------
807template<class State,class Ctrl>
809{
810 while ( !waiting.empty() )
811 {
812 typename waiting_t::iterator w = waiting.upper_bound(start_ea);
813 if ( w != waiting.begin() )
814 --w;
815 cur_ea = w->first;
816 if ( check_bounds() )
817 {
818 cur_end = BADADDR;
819 regs = w->second.regs;
820 insn_cnt = w->second.insn_cnt;
821 waiting.erase(w);
822 return fl_JF;
823 }
824 waiting.erase(w);
825 }
826 return fl_U;
827}
828
829//----------------------------------------------------------------------
830template<class State,class Ctrl>
832{
833 visited_t::iterator v = visited.upper_bound(ea);
834 // assert: v == visited.end() || v->first > ea
835 if ( v == visited.begin() )
836 return nullptr;
837 --v;
838 // assert: v->first <= ea
839 if ( ea > v->second )
840 return nullptr;
841 return &v->second;
842}
843
844
845#endif
flags64_t idaapi get_flags32(ea_t ea)
Get only 32 low bits of flags.
Definition bytes.hpp:296
idaman ea_t ida_export prev_not_tail(ea_t ea)
Get address of previous non-tail byte.
A function is a set of continuous ranges of addresses with characteristics.
Definition funcs.hpp:85
Operand of an instruction.
Definition ua.hpp:170
uint16 reg
number of register (o_reg)
Definition ua.hpp:256
uval_t value
operand value (o_imm) or outer displacement (o_displ+OF_OUTER_DISP).
Definition ua.hpp:270
optype_t type
Type of operand (see Operand types)
Definition ua.hpp:178
op_dtype_t dtype
Type of operand value (see Operand value types).
Definition ua.hpp:225
Reimplementation of vector class from STL.
Definition pro.h:2250
size_t size(void) const
Get the number of elements in the qvector.
Definition pro.h:2423
Describes a program segment.
Definition segment.hpp:69
idaman func_t *ida_export get_func(ea_t ea)
Get pointer to function structure by address.
bool func_contains(func_t *pfn, ea_t ea)
Does the given function contain the given address?
Definition funcs.hpp:305
THREAD_SAFE bool idaapi is_func(flags64_t F)
Is function start?
Definition bytes.hpp:1969
THREAD_SAFE constexpr bool idaapi is_flow(flags64_t F)
Does the previous instruction exist and pass execution flow to the current byte?
Definition bytes.hpp:913
THREAD_SAFE constexpr bool idaapi has_xref(flags64_t F)
Does the current byte have cross-references to it?
Definition bytes.hpp:928
const optype_t o_reg
General Register (al,ax,es,ds...).
Definition ua.hpp:83
const optype_t o_void
No Operand.
Definition ua.hpp:82
idaman size_t n
Definition pro.h:997
idaman segment_t *ida_export getseg(ea_t ea)
Get pointer to segment by linear address.
cref_t
CODE xref types.
Definition xref.hpp:49
@ fl_JN
Jump Near.
Definition xref.hpp:59
@ fl_U
unknown – for compatibility with old versions.
Definition xref.hpp:50
@ fl_F
Ordinary flow: used to specify execution flow to the next instruction.
Definition xref.hpp:61
@ fl_JF
Jump Far.
Definition xref.hpp:58
const tinfo_t & type
Definition hexrays.hpp:7301
THREAD_SAFE bool has_cf_chg(uint32 feature, uint opnum)
Does an instruction with the specified feature modify the i-th operand?
Definition idp.hpp:110
idaman int ida_export check_flat_jump_table(switch_info_t *si, ea_t jump_ea, int is_pattern_res=JT_SWITCH)
idaman bool ida_export check_for_table_jump(switch_info_t *si, const insn_t &insn, is_pattern_t *const patterns[], size_t qty, table_checker_t *check_table=nullptr, const char *name=nullptr)
idaman ea_t ida_export get_jtable_target(ea_t jump_ea, const switch_info_t &si, int i)
idaman ea_t ida_export find_defjump_from_table(ea_t jump_ea, const switch_info_t &si)
int table_checker_t(switch_info_t *si, ea_t jump_ea, int is_pattern_res, procmod_t *pm)
Definition jumptable.hpp:355
int is_pattern_t(switch_info_t *si, const insn_t &insn, procmod_t *procmod)
Definition jumptable.hpp:352
qvector< op_t > tracked_regs_t
Definition jumptable.hpp:97
@ JT_SWITCH
Definition jumptable.hpp:349
@ JT_NONE
Definition jumptable.hpp:349
@ JT_CALL
Definition jumptable.hpp:349
idaman void ida_export trim_jtable(switch_info_t *si, ea_t jump_ea, bool ignore_refs=false)
idaman bool ida_export find_jtable_size(switch_info_t *si)
DECLARE_JUMP_PATTERN_HELPERS(idaman) class jump_pattern_t
Definition jumptable.hpp:107
bool ok
Definition kernwin.hpp:7006
void(idaapi *range_marker)(ea_t ea
Pointer to range marker function (for idaviews and hexviews) This pointer is initialized by setup_ran...
Definitions of various information kept in netnodes.
This is the first header included in the IDA project.
int bool
Definition pro.h:329
unsigned int uint32
unsigned 32 bit value
Definition pro.h:348
uint8 op_dtype_t
Definition pro.h:460
uint64 ea_t
Definition pro.h:421
unsigned int uint
unsigned 32 bit value
Definition pro.h:339
qvector< ea_t > eavec_t
vector of addresses
Definition pro.h:2764
uint64 flags64_t
64-bit flags for each address
Definition pro.h:5009
Definition jumptable.hpp:447
State regs
Definition jumptable.hpp:448
uint insn_cnt
Definition jumptable.hpp:449
state_t()
Definition jumptable.hpp:450
visited_t visited
Definition jumptable.hpp:443
std::map< ea_t, ea_t > visited_t
Definition jumptable.hpp:442
simple_bfi_t & ctrl
Definition jumptable.hpp:429
std::map< ea_t, state_t > waiting_t
Definition jumptable.hpp:452
static void combine_insn_cnt(uint *dst, uint src)
Definition jumptable.hpp:505
ea_t * find_visited(ea_t ea)
Definition jumptable.hpp:831
cref_t prev_insn()
Definition jumptable.hpp:690
bool only_near
Definition jumptable.hpp:430
no_regs_t & regs
Definition jumptable.hpp:428
cref_t get_waiting()
Definition jumptable.hpp:808
uint max_insn_cnt
Definition jumptable.hpp:431
const segment_t * seg
Definition jumptable.hpp:436
uint insn_cnt
Definition jumptable.hpp:439
func_t * pfn
Definition jumptable.hpp:435
ea_t cur_end
Definition jumptable.hpp:438
backward_flow_iterator_t(ea_t start_ea_, State &start_regs, Ctrl &ctrl_, bool only_near_, uint max_insn_cnt_=0)
Definition jumptable.hpp:456
ea_t get_cur_end() const
Definition jumptable.hpp:493
waiting_t waiting
Definition jumptable.hpp:453
cref_t skip_block()
Definition jumptable.hpp:785
bool check_bounds() const
Definition jumptable.hpp:511
ea_t start_ea
Definition jumptable.hpp:437
Definition jumptable.hpp:521
Definition idp.hpp:2085
simple_bfi_t(ea_t ea)
Definition jumptable.hpp:531
no_regs_t regs_
Definition jumptable.hpp:528
static void combine_regs(no_regs_t *, const no_regs_t &, ea_t)
Definition jumptable.hpp:533
backward_flow_iterator_t< no_regs_t, simple_bfi_t > base_t
Definition jumptable.hpp:525
static void process_delay_slot(ea_t &, bool)
Definition jumptable.hpp:534
Information about a switch statement.
Definition nalt.hpp:710
Structure to enumerate all xrefs.
Definition xref.hpp:196
bool first_to(ea_t _to, int flags=XREF_FLOW)
Get xref to given address (store in from)
Definition xref.hpp:237
ea_t from
the referencing address - filled by first_to(),next_to()
Definition xref.hpp:197
uchar type
type of the last returned reference (cref_t & dref_t)
Definition xref.hpp:201
bool next_to()
Get next xref to address provided to first_to()
Definition xref.hpp:241
Functions that deal with the disassembling of program instructions.