IDA C++ SDK 9.2
Loading...
Searching...
No Matches
regfinder.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#pragma once
9
10#include <pro.h>
11#include <idp.hpp>
12#include <ua.hpp>
13#include <memory> // std::unique_ptr
14#include <algorithm> // std::sort
15
16//-------------------------------------------------------------------------
17/* A chain is a set of addresses where a register has the same value.
18 * Inside basic blocks, we collect these addresses by going backward until
19 * the register changes or may change its value. The instruction that
20 * changes the register value is not included in the chain.
21 * These addresses are stored in REG_USES and the value in CHAINS.
22 * If the result of an instruction that changes a value we are looking for
23 * depends on another value, we start a new chain.
24 * Example:
25 * a:=1
26 * |
27 * *<----\
28 * | |
29 * | a:=a+1
30 * | |
31 * +=====/
32 * |
33 * a?
34 *
35 * Chains are constructed in the depth-first way.
36 * This is the listing for the above example:
37 * 00 li $v0, 1 # a:=1
38 * 04 loc_4: # (*)
39 * 04 sw $v0, 0($a0) # <body>
40 * 08 sltiu $v1, $v0, 0xA
41 * 0C bnezl $v1, loc_4 # (+)
42 * 10 addiu $v0, 1 # a:=a+1 (the delay slot of a likely branch)
43 * 14 sw $a0, 0($v0) # a?
44 *
45 * after calling find_const($v0, 0x14) we get the following chains:
46 * 0=>free
47 * 1=>1@0(li) (no addresses)
48 * 2=><UNK> (04, 08, 0C, 10, 14)
49 */
50
51//-------------------------------------------------------------------------
52struct reg_value_def_t;
53#define DECLARE_REG_VALUE_DEF_HELPERS(decl)\
54decl void ida_export reg_value_def_dstr(const reg_value_def_t *_this, qstring *vout, int how, const procmod_t *pm);
55
57
58//-------------------------------------------------------------------------
62struct reg_value_def_t
63{
64 uint64 val = BADADDR;
65 ea_t def_ea = BADADDR;
66 uint16 def_itype = 0;
67 uint16 flags = 0;
68
69#define DEF_BIT static constexpr uint16
70 DEF_BIT SHORT_INSN = 0x0001;
71 DEF_BIT PC_BASED = 0x0010;
73 DEF_BIT LIKE_GOT = 0x0020;
75#undef DEF_BIT
76 static bool is_short_insn(const insn_t &insn)
77 {
78 return insn.Op2.type == o_imm && insn.Op3.type == o_void;
79 }
80
81 reg_value_def_t() {}
82 reg_value_def_t(uint64 _val, ea_t ea, uint16 _flags = 0)
83 : val(_val), def_ea(ea), flags(_flags) {}
84 reg_value_def_t(uint64 _val, const insn_t &insn, uint16 _flags = 0)
85 : val(_val),
86 def_ea(insn.ea),
87 def_itype(insn.itype),
88 flags(_flags | (is_short_insn(insn) ? SHORT_INSN : 0)) {}
89
90 bool is_short_insn() const { return (flags & SHORT_INSN) != 0; }
91 bool is_pc_based() const { return (flags & PC_BASED) != 0; }
92 bool is_like_got() const { return (flags & LIKE_GOT) != 0; }
93
94 bool operator==(const reg_value_def_t &r) const
95 {
96 return def_ea == r.def_ea && val == r.val;
97 }
98 bool operator<(const reg_value_def_t &r) const
99 {
100 if ( def_ea < r.def_ea )
101 return true;
102 if ( def_ea > r.def_ea )
103 return false;
104 return val < r.val;
105 }
106
108 enum dstr_val_t
109 {
110 NOVAL,
111 UVAL,
112 SPVAL,
113 ABORTED,
114 };
116 qstring dstr(dstr_val_t how, const procmod_t *pm = nullptr) const
117 {
118 qstring out;
119 reg_value_def_dstr(this, &out, how, pm);
120 return out;
121 }
122
123protected:
125
126 qstring dstr_impl(dstr_val_t how, const procmod_t *pm) const;
127};
128DECLARE_TYPE_AS_MOVABLE(reg_value_def_t);
129
130//-------------------------------------------------------------------------
131struct reg_value_info_t;
132#define DECLARE_REG_VALUE_INFO_HELPERS(decl)\
133decl int ida_export reg_value_info_vals_union(reg_value_info_t *_this, const reg_value_info_t *r);\
134decl void ida_export reg_value_info_dstr(const reg_value_info_t *_this, qstring *vout, const procmod_t *pm);
135
137
138//-------------------------------------------------------------------------
140struct reg_value_info_t
141{
142protected:
143 using val_def_t = reg_value_def_t;
144 friend struct reg_finder_block_t; // for join_values()
145
146 enum state_t : uint8
147 {
148 UNDEF, // we know nothing about a value
149 DEADEND, // no execution flow to the insn
150 ABORTED, // the tracking process was aborted because the maximal
151 // tracking depth is not enough to find a value or it found
152 // the huge basic block
153 BADINSN, // the insn cannot be decoded
154 UNKINSN, // the result of the insn execution is unknown
155 UNKFUNC, // the register comes from the function start
156 UNKLOOP, // the register is changed in a loop
157 UNKMULT, // the register has incompatible values
158 // (a number and SP delta)
159 UNKXREF, // too many xrefs to the address
160 UNKVALS, // the register has too many values at the address
161 NUMINSN, // the value is a number after executing the insn
162 NUMADDR, // the value is a number before the address
163 SPDINSN, // the value is a SP delta after executing the insn
164 SPDADDR, // the value is a SP delta before the address
165 };
166 // the SP delta is the value of SP minus the initial value of SP at the
167 // function start.
168 // each value (except UNDEF) may be set either before or after executing
169 // an insn at vals[i].def_ea. in the table below, these options are
170 // labeled B and A, respectively. The table shows what address is in
171 // vals[i].def_ea.
172 // the states below allow a single value
173 // DEADEND B the address of the dead end
174 // ABORTED B the address where it was aborted
175 // BADINSN A the insn address (ITYPE is not set)
176 // UNKINSN A the insn address
177 // UNKFUNC B the function start address
178 // UNKLOOP B the address of the changing insn
179 // UNKMULT B the address of the joint point
180 // UNKXREF B the address with a lot of xrefs
181 // UNKVALS B the address with a lot of values
182 // the states below allow multiple values
183 // NUMINSN A the address of the defining insn
184 // NUMADDR B the address after which the value became known
185 // SPDINSN A the address of the defining insn
186 // SPDADDR B the address after which the value became known
187
188 qvector<val_def_t> vals; // sorted
189 state_t state = UNDEF;
190
191 explicit reg_value_info_t(
192 state_t _state,
193 ea_t def_ea,
194 uval_t _val = BADADDR,
195 uint16 val_flags = 0)
196 : state(_state)
197 {
198 vals.push_back(val_def_t(_val, def_ea, val_flags));
199 }
200 explicit reg_value_info_t(
201 state_t _state,
202 const insn_t &insn,
203 uval_t _val = BADADDR,
204 uint16 val_flags = 0)
205 : state(_state)
206 {
207 vals.push_back(val_def_t(_val, insn, val_flags));
208 }
209
210public:
211 reg_value_info_t() {}
213 void clear()
214 {
215 state = UNDEF;
216 vals.qclear();
217 }
219 bool empty() const { return state == UNDEF; }
220
221 void swap(reg_value_info_t &r) noexcept
222 {
223 std::swap(state, r.state);
224 vals.swap(r.vals);
225 }
226
229 static reg_value_info_t make_dead_end(ea_t dead_end_ea)
230 {
231 return reg_value_info_t(DEADEND, dead_end_ea);
232 }
233
236 static reg_value_info_t make_aborted(
237 ea_t bblk_ea,
238 int aborting_depth = -1)
239 {
240 return reg_value_info_t(ABORTED, bblk_ea, uint32(aborting_depth));
241 }
242
245 static reg_value_info_t make_badinsn(ea_t insn_ea)
246 {
247 return reg_value_info_t(BADINSN, insn_ea);
248 }
249
252 static reg_value_info_t make_unkinsn(const insn_t &insn)
253 {
254 return reg_value_info_t(UNKINSN, insn);
255 }
256
259 static reg_value_info_t make_unkfunc(ea_t func_ea)
260 {
261 return reg_value_info_t(UNKFUNC, func_ea);
262 }
263
266 static reg_value_info_t make_unkloop(ea_t bblk_ea)
267 {
268 return reg_value_info_t(UNKLOOP, bblk_ea);
269 }
270
273 static reg_value_info_t make_unkmult(ea_t bblk_ea)
274 {
275 return reg_value_info_t(UNKMULT, bblk_ea);
276 }
277
280 static reg_value_info_t make_unkxref(ea_t bblk_ea)
281 {
282 return reg_value_info_t(UNKXREF, bblk_ea);
283 }
284
287 static reg_value_info_t make_unkvals(ea_t bblk_ea)
288 {
289 return reg_value_info_t(UNKVALS, bblk_ea);
290 }
291
294 static reg_value_info_t make_num(
295 uval_t rval,
296 const insn_t &insn,
297 uint16 val_flags = 0)
298 {
299 return reg_value_info_t(NUMINSN, insn, rval, val_flags);
300 }
303 static reg_value_info_t make_num(
304 uval_t rval,
305 ea_t val_ea,
306 uint16 val_flags = 0)
307 {
308 return reg_value_info_t(NUMADDR, val_ea, rval, val_flags);
309 }
310
313 static reg_value_info_t make_initial_sp(ea_t func_ea)
314 {
315 return reg_value_info_t(SPDADDR, func_ea, 0);
316 }
317
318 //-----------------------------------------------------------------------
319 // access methods
320
322 bool is_dead_end() const { return state == DEADEND; }
324 bool aborted() const { return state == ABORTED; }
326 bool is_special() const { return is_dead_end() || aborted(); }
327
329 bool is_badinsn() const { return state == BADINSN; }
331 bool is_unkinsn() const { return state == UNKINSN; }
333 bool is_unkfunc() const { return state == UNKFUNC; }
335 bool is_unkloop() const { return state == UNKLOOP; }
338 bool is_unkmult() const { return state == UNKMULT; }
340 bool is_unkxref() const { return state == UNKXREF; }
343 bool is_unkvals() const { return state == UNKVALS; }
345 bool is_unknown() const
346 {
347 return state == BADINSN
348 || state == UNKINSN
349 || state == UNKFUNC
350 || state == UNKLOOP
351 || state == UNKMULT
352 || state == UNKXREF
353 || state == UNKVALS;
354 }
355
357 bool is_num() const { return state == NUMINSN || state == NUMADDR; }
359 bool is_spd() const { return state == SPDINSN || state == SPDADDR; }
361 bool is_known() const { return is_num() || is_spd(); }
362
365 bool get_num(uval_t *uval) const
366 {
367 if ( !is_num() || !is_value_unique() )
368 return false;
369 *uval = vals.begin()->val;
370 return true;
371 }
376 bool get_spd(sval_t *sval) const
377 {
378 if ( !is_spd() || !is_value_unique() )
379 return false;
380 *sval = int64(vals.begin()->val);
381 return true;
382 }
384 ea_t get_def_ea() const
385 {
386 return !is_value_unique() ? BADADDR : vals.begin()->def_ea;
387 }
389 uint16 get_def_itype() const
390 {
391 return !is_value_unique() ? 0 : vals.begin()->def_itype;
392 }
394 int get_aborting_depth() const
395 {
396 if ( !aborted() || !is_value_unique() )
397 return -1;
398 return int32(vals.begin()->val);
399 }
400
402 const reg_value_def_t *vals_begin() const { return vals.begin(); }
404 const reg_value_def_t *vals_end() const { return vals.end(); }
406 size_t vals_size() const { return vals.size(); }
407
409 bool is_value_unique() const
410 {
411 if ( empty() )
412 return false;
413 if ( vals.size() == 1 )
414 return true;
415 auto p = vals.begin();
416 uint64 v = p->val;
417 for ( ++p; p != vals.end(); ++p )
418 if ( p->val != v )
419 return false;
420 return true;
421 }
422
424 bool have_all_vals_flag(uint16 val_flags) const
425 {
426 for ( auto p : vals )
427 if ( (p.flags & val_flags) == 0 )
428 return false;
429 return true;
430 }
431 bool has_any_vals_flag(uint16 val_flags) const
432 {
433 for ( auto p : vals )
434 if ( (p.flags & val_flags) != 0 )
435 return true;
436 return false;
437 }
438 bool is_all_vals_pc_based() const
439 {
440 return have_all_vals_flag(val_def_t::PC_BASED);
441 }
442 bool is_any_vals_pc_based() const
443 {
444 return has_any_vals_flag(val_def_t::PC_BASED);
445 }
446 bool is_all_vals_like_got() const
447 {
448 return have_all_vals_flag(val_def_t::LIKE_GOT);
449 }
450 bool is_any_vals_like_got() const
451 {
452 return has_any_vals_flag(val_def_t::LIKE_GOT);
453 }
454
456 void set_all_vals_flag(uint16 val_flags)
457 {
458 for ( auto &p : vals )
459 p.flags |= val_flags;
460 }
461 void set_all_vals_pc_based()
462 {
463 return set_all_vals_flag(val_def_t::PC_BASED);
464 }
465 void set_all_vals_got_based()
466 {
467 return set_all_vals_flag(val_def_t::LIKE_GOT);
468 }
469
470 //-----------------------------------------------------------------------
471 // modification methods
472
475 void set_dead_end(ea_t dead_end_ea)
476 {
477 state = DEADEND;
478 vals.qclear();
479 vals.push_back(val_def_t(BADADDR, dead_end_ea));
480 }
481
484 void set_badinsn(ea_t insn_ea)
485 {
486 state = BADINSN;
487 vals.qclear();
488 vals.push_back(val_def_t(BADADDR, insn_ea));
489 }
490
493 void set_unkinsn(const insn_t &insn)
494 {
495 state = UNKINSN;
496 vals.qclear();
497 vals.push_back(val_def_t(BADADDR, insn));
498 }
499
502 void set_unkfunc(ea_t func_ea)
503 {
504 state = UNKFUNC;
505 vals.qclear();
506 vals.push_back(val_def_t(BADADDR, func_ea));
507 }
508
511 void set_unkloop(ea_t bblk_ea)
512 {
513 state = UNKLOOP;
514 vals.qclear();
515 vals.push_back(val_def_t(BADADDR, bblk_ea));
516 }
517
520 void set_unkmult(ea_t bblk_ea)
521 {
522 state = UNKMULT;
523 vals.qclear();
524 vals.push_back(val_def_t(BADADDR, bblk_ea));
525 }
526
529 void set_unkxref(ea_t bblk_ea)
530 {
531 state = UNKXREF;
532 vals.qclear();
533 vals.push_back(val_def_t(BADADDR, bblk_ea));
534 }
535
538 void set_unkvals(ea_t bblk_ea)
539 {
540 state = UNKVALS;
541 vals.qclear();
542 vals.push_back(val_def_t(BADADDR, bblk_ea));
543 }
544
547 void set_aborted(ea_t bblk_ea, int aborting_depth = -1)
548 {
549 state = ABORTED;
550 vals.qclear();
551 vals.push_back(val_def_t(uint32(aborting_depth), bblk_ea));
552 }
553
556 void set_num(uval_t rval, const insn_t &insn, uint16 val_flags = 0)
557 {
558 state = NUMINSN;
559 vals.qclear();
560 vals.push_back(val_def_t(rval, insn, val_flags));
561 }
565 void set_num(uvalvec_t *rvals, const insn_t &insn)
566 {
567 state = NUMINSN;
568 set_multivals(rvals, insn);
569 }
572 void set_num(uval_t rval, ea_t val_ea, uint16 val_flags = 0)
573 {
574 state = NUMADDR;
575 vals.qclear();
576 vals.push_back(val_def_t(rval, val_ea, val_flags));
577 }
578
580 enum set_compare_res_t
581 {
582 EQUAL,
583 CONTAINS,
584 CONTAINED,
585 NOT_COMPARABLE,
586 };
593 set_compare_res_t vals_union(const reg_value_info_t &r)
594 {
595 return set_compare_res_t(reg_value_info_vals_union(this, &r));
596 }
597
601 inline void extend(const procmod_t &pm, int width, bool is_signed);
602
605 inline void trunc_uval(const procmod_t &pm);
606
607 // arithmetic operations
608 enum arith_op_t
609 {
610 ADD, SUB,
611 OR, AND, XOR, AND_NOT,
612 SLL, SLR, SAR, MOVT,
613 NEG, NOT,
614 };
615
618 inline void add(const reg_value_info_t &r, const insn_t &insn);
621 inline void sub(const reg_value_info_t &r, const insn_t &insn);
625 inline void bor(const reg_value_info_t &r, const insn_t &insn);
629 inline void band(const reg_value_info_t &r, const insn_t &insn);
633 inline void bxor(const reg_value_info_t &r, const insn_t &insn);
637 inline void bandnot(const reg_value_info_t &r, const insn_t &insn);
640 inline void sll(const reg_value_info_t &r, const insn_t &insn);
644 inline void slr(const reg_value_info_t &r, const insn_t &insn);
648 inline void sar(const reg_value_info_t &r, const insn_t &insn);
652 inline void movt(const reg_value_info_t &r, const insn_t &insn);
654 inline void neg(const insn_t &insn);
657 inline void bnot(const insn_t &insn);
660 inline void add_num(uval_t r, const insn_t &insn);
661
664 inline void add_num(uval_t r);
667 inline void shift_left(uval_t r);
670 inline void shift_right(uval_t r);
671
673 qstring dstr(const procmod_t *pm = nullptr) const
674 {
675 qstring out;
676 reg_value_info_dstr(this, &out, pm);
677 return out;
678 }
679
680protected:
682
683 // helper implementation
684 set_compare_res_t vals_union_impl(const reg_value_info_t &r);
685 qstring dstr_impl(const procmod_t *pm) const;
686
687 // perform a binary operation
688 // \note Either THIS or R must have a single value.
689 inline bool perform_binary_op(
690 const reg_value_info_t &r,
691 arith_op_t aop,
692 const insn_t &insn);
693 // fix the sorting order and set VALS
694 template<class V>
695 inline void set_multivals(V *rvals, const insn_t &insn);
696 // fix the sorting order
697 inline void sort_multivals();
698};
699
700//-------------------------------------------------------------------------
701// what operand are we going to track?
702struct reg_finder_op_t
703{
704private:
705 // |31 |30-29|28 |...
706 // |reg or stkvar|width|signness|...
707 // for registers:
708 // ...|27-16 |15-0 |
709 // ...|reserved|register number|
710 // for stkvars:
711 // ...|27 |26-0 |
712 // ...|stkoff sign|stkoff absolute value|
713 static constexpr uint32 REG = 0;
714 static constexpr uint32 STKVAR = 1 << 31;
715 static constexpr int WIDTH_SHIFT = 29;
716 static constexpr uint32 WIDTH_MASK = 0x3 << WIDTH_SHIFT;
717 static constexpr uint32 SIGNED = 1 << 28;
718 static constexpr int STKOFF_SIGNBIT = 1 << 27;
719 static constexpr uint32 STKOFF_MASK = STKOFF_SIGNBIT - 1;
720 // the impossible combination of bits
721 static constexpr uint32 BADREG = 0x10000;
722
723 uint32 packed = BADREG;
724
725 explicit reg_finder_op_t(uint32 _packed) : packed(_packed) {}
726
727public:
728 using rfop_t = reg_finder_op_t;
730 reg_finder_op_t(const rfop_t &r) = default;
731 rfop_t &operator=(const rfop_t &r) = default;
732
733 // if after constructors empty() returns 'true'
734 // that means that arguments are bad
735 bool empty() const { return packed == BADREG; }
736 void clear() { packed = BADREG; }
737
738 static bool is_valid_reg(int reg)
739 {
740 return reg >= 0 && reg < BADREG;
741 }
742 inline static reg_finder_op_t make_reg(int reg, int width);
743 static reg_finder_op_t make_reg(const procmod_t &pm, int reg)
744 {
745 return make_reg(reg, pm.eah().ea_size); // 4 or 8
746 }
747
748 static bool is_valid_stkoff(sval_t stkoff)
749 {
750 return stkoff >= -sval_t(STKOFF_MASK) && stkoff <= sval_t(STKOFF_MASK);
751 }
752 inline static reg_finder_op_t make_stkoff(sval_t stkoff, int width);
753 inline static int get_op_width(const op_t &op);
754
755 inline void set_width(int width);
756 inline void set_signness(bool is_signed);
757 inline void set_width_signness(int width, bool is_signed);
758
759 bool is_reg() const { return (packed & STKVAR) == 0; }
760 bool is_stkvar() const { return (packed & STKVAR) != 0; }
761 bool is_signed() const { return (packed & SIGNED) != 0; }
762 int get_width() const
763 {
764 return 1 << ((packed & WIDTH_MASK) >> WIDTH_SHIFT);
765 }
766
767 uint16 get_reg() const { return uint16(packed); }
769 {
770 sval_t stkoff = packed & STKOFF_MASK;
771 return (packed & STKOFF_SIGNBIT) == 0 ? stkoff : -stkoff;
772 }
773
774 bool is_reg(int reg) const { return is_reg() && get_reg() == reg; }
775
776 DECLARE_COMPARISONS(reg_finder_op_t)
777 {
778 // the empty object is less than any other object
779 if ( empty() )
780 return r.empty() ? 0 : -1;
781 if ( r.empty() )
782 return 1;
783 return ::compare(packed, r.packed);
784 }
785
786
787protected:
788 inline static uint32 pack_width(int width);
789};
790
791//-------------------------------------------------------------------------
792struct reg_finder_t;
793struct reg_value_ud_chain_t;
795 reg_value_info_t *v1,
796 reg_value_info_t *v2,
797 const insn_t &insn,
798 void *ud);
799
800#define DECLARE_REG_FINDER_HELPERS(decl)\
801decl void ida_export reg_finder_invalidate_cache(reg_finder_t *_this, ea_t to, ea_t from, cref_t cref);\
802decl void ida_export reg_finder_invalidate_xrefs_cache(reg_finder_t *_this, ea_t ea, dref_t dref);\
803decl void ida_export reg_finder_find(reg_finder_t *_this, reg_value_info_t *out, ea_t ea, ea_t ds, reg_finder_op_t op, int max_depth, size_t linear_insns);\
804decl void ida_export reg_finder_make_rfop(reg_finder_t *_this, reg_finder_op_t *rfop, const op_t *op, const insn_t *insn, func_t *pfn);\
805decl bool ida_export reg_finder_calc_op_addr(reg_finder_t *_this, reg_value_info_t *addr, const op_t *memop, const insn_t *insn, ea_t ea, ea_t ds, int max_depth);\
806decl bool ida_export reg_finder_emulate_mem_read(reg_finder_t *_this, reg_value_info_t *value, const reg_value_info_t *addr, int width, bool is_signed, const insn_t *insn);\
807decl void ida_export reg_finder_emulate_binary_op(reg_finder_t *_this, reg_value_info_t *value, int aop, const op_t *op1, const op_t *op2, const insn_t *insn, ea_t ea, ea_t ds, reg_finder_binary_ops_adjust_fun adjust, void *ud);\
808decl void ida_export reg_finder_emulate_unary_op(reg_finder_t *_this, reg_value_info_t *value, int aop, int reg, const insn_t *insn, ea_t ea, ea_t ds);\
809decl bool ida_export reg_finder_may_modify_stkvar(reg_finder_t *_this, reg_value_info_t *value, reg_finder_op_t op, const insn_t *insn);\
810decl bool ida_export reg_finder_can_resolve_mem(const reg_finder_t *_this, ea_t ea);\
811decl void ida_export reg_finder_ctr(reg_finder_t *_this);\
812decl void ida_export reg_finder_dtr(reg_finder_t *_this);
813
815
816//-------------------------------------------------------------------------
817//lint -e{958} padding needed
818struct reg_finder_block_t;
819struct reg_finder_pred_t;
821{
822 const procmod_t &pm;
823 const int proc_maxop; // max number of operands in insns
824
825 uint32 flags; // a set of RF_... bits
826
827 // a call insn may modify stkvars (via aliased stkvars passed as args).
828 // this bit indicates how to answer this question.
829 static constexpr uint32 RF_DOES_CALL_SPOIL_STKVARS = 0x0001;
830 // this bit allows to use the write-xrefs cache. if it is set then the
831 // proc module has to call invalidate_xrefs_cache() on the events:
832 // - ev_add_dref
833 // - ev_del_dref
834 static constexpr uint32 RF_ALLOW_XREFS_CACHE = 0x0002;
835
837 {
838 return (flags & RF_DOES_CALL_SPOIL_STKVARS) != 0;
839 }
840 bool allow_xrefs_cache() const
841 {
842 return (flags & RF_ALLOW_XREFS_CACHE) != 0;
843 }
844
845protected:
846 using rvi_t = reg_value_info_t;
850 friend struct reg_finder_block_t;
851 friend struct reg_finder_pred_t;
852
853 // the data members below are set by the each call of find()
854 func_t *cur_func = nullptr; // function to search in
856 bool fixed_max_depth = false; // is the initial MAX_DEPTH specified by the
857 // caller (not taken from ida.cfg) ?
858 int cur_max_depth = 0; // maximum search depth
859 int cur_call_depth = 0; // the current depth of recursive calls
860 size_t linear_flow_cnt = 0; // the number of insn to search in the
861 // linear flow (if != 0)
862 bool only_linear_flow() const { return linear_flow_cnt != 0; }
863 size_t bblk_cnt = 0; // the number of insn in a basic block
864 ea_t aborting_ea = BADADDR; // to make tracking aborting easier
865 rvi_t standalone_value; // to return a value for the initial block
866 // without addresses
867
868 static constexpr size_t NO_CHAIN = size_t(-1);
869
870 // a temporary storage to return from is_move_insn()
873
874 // the condition under which the instruction is executed,
875 // and some additional instruction features
876 struct cond_t
877 {
878 private:
879 uint32 packed;
880 static constexpr uint32 COND_MASK = 0x0F;
881 static constexpr int KIND_SHIFT = 4;
882 static constexpr uint32 KIND_MASK = 0xF;
883
884 public:
885 // got from arm.hpp
886 enum : uchar
887 {
888 EQ, // 0000 Z Equal
889 NE, // 0001 !Z Not equal
890 CS, // 0010 C Unsigned higher or same
891 CC, // 0011 !C Unsigned lower
892 MI, // 0100 N Negative
893 PL, // 0101 !N Positive or Zero
894 VS, // 0110 V Overflow
895 VC, // 0111 !V No overflow
896 HI, // 1000 C & !Z Unsigned higher
897 LS, // 1001 !C | Z Unsigned lower or same
898 GE, // 1010 (N & V) | (!N & !V) Greater or equal
899 LT, // 1011 (N & !V) | (!N & V) Less than
900 GT, // 1100 !Z & ((N & V)|(!N & !V)) Greater than
901 LE, // 1101 Z | (N & !V) | (!N & V) Less than or equal
902 AL, // 1110 Always
903 NV, // 1111 Never
904 };
905
906 enum : uchar
907 {
911 };
912
913 cond_t(uchar cond = AL, uchar kind = NONE)
914 : packed((cond & COND_MASK) | ((kind & KIND_MASK) << KIND_SHIFT)) {}
915
916 uchar get_cond() const { return uchar(packed & COND_MASK); }
917 // e.g. GE includes GE, GT, EQ
918 // MOVGE ... this insn is executed if the branch is taken
919 // BGT away
920 bool is_included_in(cond_t r) const
921 {
922 // TODO implement non-trivial cases
923 uchar cnd = get_cond();
924 uchar rcnd = r.get_cond();
925 // AL includes all other conditions
926 return cnd == rcnd || rcnd == AL;
927 }
928
930 {
931 return uchar((packed >> KIND_SHIFT) & KIND_MASK);
932 }
933 bool modifies_cond_codes() const { return get_kind() == MODIFIES_CC; }
934 bool jumps() const { return get_kind() == JUMPS; }
935 };
936
937private:
938 using udc_t = reg_value_ud_chain_t;
939
941 struct reg_finder_chainvec_t *chains = nullptr; // the chain values
942
943 struct addr_t
944 {
945 ea_t ea;
946 rfop_t rfop;
947 addr_t(ea_t _ea, rfop_t _rfop = rfop_t()) : ea(_ea), rfop(_rfop) {}
948 DECLARE_COMPARISONS(addr_t)
949 {
950 int code = ::compare(ea, r.ea);
951 if ( code == 0 )
952 code = rfop.compare(r.rfop);
953 return code;
954 }
955 };
956 // where does the value come from?
957 struct vref_t
958 {
959 size_t chain_num; // the chain number
960 sval_t delta; // the addend to the chain value
961 explicit vref_t(
962 size_t _chain_num = reg_finder_t::NO_CHAIN,
963 sval_t _delta = 0)
964 : chain_num(_chain_num), delta(_delta) {}
965 bool empty() const { return chain_num == reg_finder_t::NO_CHAIN; }
966 void clear() { chain_num = reg_finder_t::NO_CHAIN; delta = 0; }
967 bool operator==(const vref_t &r)
968 {
969 return chain_num == r.chain_num && delta == r.delta;
970 }
971 };
972
973 // key - an operand and an address,
974 // value - the reference to the value of the register at this address
975 // (the chain value + DELTA)
976 friend struct reg_finder_rfop_chains_t; // the opaque type
977 struct reg_finder_rfop_chains_t *rfop_chains = nullptr;
978
979 // the path of depth-first search
980 qvector<vref_t> path;
981
982 // the cache of the write xrefs of addresses in read-only segments.
983 // this cache is used only if the regfinder is created with the
984 // RF_ALLOW_XREFS_CACHE bit.
985 friend struct reg_finder_xrefs_cache_t; // the opaque type
986 struct reg_finder_xrefs_cache_t *xrefs_cache = nullptr;
987
988 bool in_invalidate = false; // the guard for invalidate_regfinder_cache()
989 bool debug_on = true;
990
991public:
993 const procmod_t &_pm,
994 int _proc_maxop = 3,
996 : pm(_pm),
997 proc_maxop(_proc_maxop),
998 flags(_flags)
999 {
1000 reg_finder_ctr(this);
1001 }
1002 virtual ~reg_finder_t() { reg_finder_dtr(this); }
1003
1004 // the code xref from FROM to TO was added or deleted.
1005 // if we have TO address in the cache we should invalidate the value at
1006 // this address and the dependent values.
1007 void invalidate_cache(ea_t to, ea_t from, cref_t cref)
1008 {
1009 reg_finder_invalidate_cache(this, to, from, cref);
1010 }
1011 // clear the entire cache.
1013 {
1014 reg_finder_invalidate_cache(this, BADADDR, BADADDR, fl_U);
1015 }
1016
1017 // a new data xref to EA was added or deleted.
1018 // \sa RF_ALLOW_XREFS_CACHE
1020 {
1021 reg_finder_invalidate_xrefs_cache(this, ea, dref);
1022 }
1023
1024 // find a value of OP before EA
1025 // \param max_depth the maximum search depth.
1026 // 0 means the value of REGTRACK_MAX_DEPTH or
1027 // REGTRACK_FUNC_MAX_DEPTH from ida.cfg depending on the
1028 // register,
1029 // -1 means always the value of REGTRACK_FUNC_MAX_DEPTH.
1030 // A value greater than 1 cannot be used in recursive
1031 // calls of find() (e.g. from emulate_insn()).
1032 // \param linear_insns a non-zero value causes switching to the linear
1033 // flow search mode. In this mode the search stops at
1034 // the first xref or when LINEAR_INSNS insns are
1035 // tracked. The number of instructions tracked is
1036 // counted from the address of the first call with a
1037 // non-zero argument, i.e. recursive calls to find()
1038 // after switching to this mode ignore this argument.
1040 ea_t ea,
1041 rfop_t rfop,
1042 int max_depth = 0,
1043 size_t linear_insns = 0)
1044 {
1045 rvi_t ret;
1046 flow_t flow = process_delay_slot(pm.trunc_uval(ea), fl_U);
1047 reg_finder_find(this, &ret,
1048 flow.ea, flow.ds, rfop,
1049 max_depth, linear_insns);
1050 return ret;
1051 }
1052
1053 // find the value of any of the two registers
1055 reg_value_info_t *rvi,
1056 ea_t ea,
1057 const int reg[2],
1058 size_t linear_insns = 10)
1059 {
1060 if ( reg[0] == reg[1] )
1061 return -1;
1062 *rvi = find(ea, rfop_t::make_reg(pm, reg[0]), 0, linear_insns);
1063 if ( rvi->is_known() )
1064 return 0;
1065 *rvi = find(ea, rfop_t::make_reg(pm, reg[1]), 0, linear_insns);
1066 if ( rvi->is_known() )
1067 return 1;
1068 *rvi = find(ea, rfop_t::make_reg(pm, reg[0]), 0);
1069 if ( rvi->is_known() )
1070 return 0;
1071 *rvi = find(ea, rfop_t::make_reg(pm, reg[1]), 0);
1072 if ( rvi->is_known() )
1073 return 1;
1074 return -1;
1075 }
1076
1077 // find a value of non-SP based register before EA
1078 bool find_const(uval_t *val, ea_t ea, rfop_t rfop, int max_depth = 0)
1079 {
1080 return find(ea, rfop, max_depth).get_num(val);
1081 }
1082
1083 // find a value of SP based register before EA
1084 // by default it uses the SP register and REGTRACK_FUNC_MAX_DEPTH
1085 bool find_spd(sval_t *spval, ea_t ea, int reg = -1, int max_depth = -1)
1086 {
1087 if ( reg == -1 )
1088 {
1089 reg = get_sp_reg(ea);
1090 if ( reg == -1 )
1091 return false;
1092 }
1093 return find(ea, rfop_t::make_reg(pm, reg), max_depth).get_spd(spval);
1094 }
1095
1096 // make the regfinder operand from the insn operand.
1097 // if OP is unsupported this function returns an empty operand.
1098 rfop_t make_rfop(const op_t &_op, const insn_t &insn, func_t *pfn)
1099 {
1100 op_t op = _op; // make a copy
1101 if ( !can_track_op(&op, insn, pfn) )
1102 return rfop_t();
1103 rfop_t res;
1104 reg_finder_make_rfop(this, &res, &op, &insn, pfn);
1105 aborting_ea = BADADDR; // ignore for this call
1106 return res;
1107 }
1108
1109 // find the operand addresses (o_displ or o_phrase or o_mem)
1110 // \li in the case of 'o_displ', the address is formed by adding
1111 // memop.addr to the content of memop.phrase
1112 // \li in the case of 'o_phrase', the address is formed by adding
1113 // memop.addr to the sum of the content of memop.phrase and the content of
1114 // the second register (memop.value), \sa procmod_t::make_op_phrase()
1115 // \li in the case of 'o_mem', the address is just memop.addr
1116 // \param memop the operand
1117 // \param insn the emulated insn
1118 // \param max_depth the maximum search depth.
1120 const op_t &memop,
1121 const insn_t &insn,
1122 int max_depth = 0)
1123 {
1124 rvi_t ret;
1125 flow_t flow = process_delay_slot(pm.trunc_uval(insn.ea), fl_U);
1126 reg_finder_calc_op_addr(this, &ret,
1127 &memop,
1128 &insn, flow.ea, flow.ds, max_depth);
1129 return ret;
1130 }
1131
1132 // handle a memory read
1133 // \note this method checks that the address belongs to the readonly
1134 // segment, if not it calls is_mem_readonly() to make an additional
1135 // check.
1136 // \param addr the address to read from.
1137 // this parameter may be the same as VALUE.
1138 // \param width the data width. it must be 1/2/4/8.
1139 // \sa get_data_value()
1140 // \param is_signed if 'true' the result should be sign-extended
1141 // \param insn the emulated insn
1143 rvi_t *value,
1144 const rvi_t &addr,
1145 int width,
1146 bool is_signed,
1147 const insn_t &insn)
1148 {
1149 reg_finder_emulate_mem_read(this, value, &addr,
1150 width, is_signed,
1151 &insn);
1152 }
1153
1154 // is memory at EA read-only?
1155 bool can_resolve_mem(ea_t ea) const
1156 {
1157 return reg_finder_can_resolve_mem(this, ea);
1158 }
1159
1160
1161protected:
1162 // the address of the emulated instruction, taking into account a possible
1163 // delay slot
1164 struct flow_t
1165 {
1167 ea_t ds; // to handle a delay slot
1168 bool has_delay_slot() const { return ds != BADADDR; }
1169 // pre-condidition: has_delay_slot()
1170 bool is_ea_handled() const { return ds > ea; }
1171 // pre-condidition: is_ea_handled()
1173
1174 flow_t(ea_t _ea, ea_t _ds = BADADDR) : ea(_ea), ds(_ds) {}
1175
1176 // the address of the actually emulated insn
1177 // when handling a delay slot we are actually emulating the main insn
1178 // 00 func:
1179 // 00 beq ..., @away # $t9 is not 00 because it is modified in the
1180 // # delay slot
1181 // 04 addui $t9, ... # $t9 is 00 before this insn
1182 ea_t actual_ea() const { return has_delay_slot() ? ds : ea; }
1183 operator ea_t() const { return actual_ea(); }
1184
1185 bool operator<(const flow_t &r) const { return ea < r.ea; }
1186
1187 };
1188
1189 // processor specific methods
1190
1191 // we reached EA using REF.
1192 // For processors with delay slots we can process another insn first.
1193 // 00 jal main
1194 // 04 addiu $a1, $v0, 4 <-- EA but we should start with 00
1195 // \param ref how did we reach EA?
1196 // - fl_F: by the ordinary flow,
1197 // - fl_JN, fl_JF: by the jump,
1198 // - fl_U: from the find() method.
1199 virtual flow_t process_delay_slot(ea_t ea, cref_t /*ref*/) const
1200 {
1201 return flow_t(ea); // no delay slots
1202 }
1203
1204 // an instruction may be executed under a condition
1205 virtual cond_t get_cond(ea_t ea) const
1206 {
1207 qnotused(ea);
1208 return cond_t(); // no conditional instructions
1209 }
1210
1211 // we may know the value of some registers
1212 // \retval empty() we know nothing
1213 // \retval is_unkfunc() there may be any value (e.g. a func argument)
1214 // \retval is_known() we found the value (e.g. the GOT register)
1216 flow_t flow,
1217 rfop_t rfop,
1218 bool is_func_start) const
1219 {
1220 qnotused(rfop);
1221 qnotused(flow);
1222 qnotused(is_func_start);
1223 return rvi_t(); // know nothing about registers
1224 }
1225
1226 // is the content of memory at EA a constant?
1227 // \note this method is called from emulate_mem_read() if it cannot itself
1228 // determine that this memory is read-only.
1229 virtual bool is_mem_readonly(ea_t /*ea*/) const
1230 {
1231 return false;
1232 }
1233
1234 // get the SP register
1235 virtual int get_sp_reg(ea_t ea) const
1236 {
1237 qnotused(ea);
1238 return -1;
1239 }
1240
1241 // is REG used throughout the function?
1242 virtual bool is_funcwide_reg(ea_t ea, int reg) const
1243 {
1244 return reg == get_sp_reg(ea);
1245 }
1246
1247 // we can track only registers and stkvars (including BP-based)
1248 virtual bool can_track_op(op_t *op, const insn_t &insn, func_t *pfn) const
1249 {
1250 qnotused(op);
1251 qnotused(insn);
1252 qnotused(pfn);
1253 return false;
1254 }
1255
1256 // is INSN a 'move' instruction? (or a simple add/sub instruction)
1258 {
1259 // the first case (if !new_rfop.empty()):
1260 // is_move_insn() already knows the new tracked operand
1262
1263 // the second case (if new_rfop.empty()):
1264 // the operand types should be byte/word/dword/qword
1265 // both DST_OP and SRC_OP cannot be memory operands
1266 // the pointer to the source operand
1267 const op_t *dst_op = nullptr;
1268 // the pointer to the destination operand
1269 const op_t *src_op = nullptr;
1270 // if 'true' and DST_OP is wider than SRC_OP then the source operand
1271 // will be sign extended
1272 bool is_signed = false;
1273
1274 // if non-zero then the instruction is a simple 'add/sub' insn with an
1275 // immediate value. the operands must have the same size.
1276 // \note this member is used by both cases.
1277 // DELTA is positive for the 'add' insn.
1279 };
1280 // \param [out] move_desc the decription of the 'move' insn
1281 // \param [in] rfop the operand to find a value of
1282 // \param insn the emulating insn
1283 // \retval false if INSN is not a 'move' insn
1284 // \retval true INSN is a 'move' insn
1285 virtual bool is_move_insn(
1286 move_desc_t *move_desc,
1287 const rfop_t &rfop,
1288 const insn_t &insn)
1289 {
1290 qnotused(move_desc);
1291 qnotused(rfop);
1292 qnotused(insn);
1293 return false;
1294 }
1295
1296 // emulate INSN and find the value of OP
1297 // to get values of the source registers this method may call find()
1298 // (this call will be recursive)
1299 // \param [out] value only if the method returns 'true'
1300 // is_dead_end(): there is no flow to this insn
1301 // aborted(): the tracking process was aborted
1302 // is_unkinsn(): INSN spoils OP in an unknown way
1303 // is_known(): the found value
1304 // \param [in] rfop the operand to find a value of
1305 // \param [in] insn the instruction to emulate
1306 // \param [in] flow the control flow to get a preceding insn.
1307 // it will be passed to find().
1308 // \retval true the found value is in VALUE
1309 // \retval false INSN does not modify OP
1310 virtual bool emulate_insn(
1311 rvi_t *value,
1312 const rfop_t &rfop,
1313 const insn_t &insn,
1314 flow_t flow)
1315 {
1316 qnotused(rfop);
1317 qnotused(flow);
1318 value->set_unkinsn(insn); // do not support any instruction
1319 return true;
1320 }
1321
1322 // helper methods for emulate_insn()
1323
1324 // get values of the operand from emulate_insn()
1325 // \param flow the control flow to get a starting insn
1326 // \param rfop the operand to find a value of
1328 {
1329 rvi_t ret;
1330 reg_finder_find(this, &ret, flow.ea, flow.ds, rfop, 0, 0);
1331 return ret;
1332 }
1333
1334 // get values of the register from emulate_insn()
1335 // \param flow the control flow to get a starting insn
1336 // \param reg the register to find a value of
1337 rvi_t find(flow_t flow, int reg)
1338 {
1339 rvi_t ret;
1340 rfop_t rfop = rfop_t::make_reg(pm, reg);
1341 reg_finder_find(this, &ret, flow.ea, flow.ds, rfop, 0, 0);
1342 return ret;
1343 }
1344
1345 // get operand addresses (o_displ or o_phrase or o_mem)
1346 // \sa find_op_addr()
1348 rvi_t *addr,
1349 const op_t &memop,
1350 const insn_t &insn,
1351 flow_t flow)
1352 {
1353 reg_finder_calc_op_addr(this, addr,
1354 &memop,
1355 &insn, flow.ea, flow.ds, 0);
1356 }
1357
1359 rvi_t *value,
1360 rvi_t::arith_op_t aop, // not NEG, NOT
1361 const op_t &op1,
1362 const op_t &op2,
1363 const insn_t &insn,
1364 flow_t flow,
1365 reg_finder_binary_ops_adjust_fun adjust = nullptr,
1366 void *ud = nullptr)
1367 {
1368 reg_finder_emulate_binary_op(this, value,
1369 aop, &op1, &op2,
1370 &insn, flow.ea, flow.ds,
1371 adjust, ud);
1372 }
1374 rvi_t *value,
1375 rvi_t::arith_op_t aop, // only NEG, NOT
1376 int reg,
1377 const insn_t &insn,
1378 flow_t flow)
1379 {
1380 reg_finder_emulate_unary_op(this, value,
1381 aop, reg,
1382 &insn, flow.ea, flow.ds);
1383 }
1384
1385 // this method returns 'true' and sets VALUE to UNKINSN if there is the
1386 // slightest possibility that INSN changes OP (it is a stkvar).
1387 // in the current implementation we assume that any store instruction with
1388 // an unknown address or any call instruction may modify stkvars.
1389 bool may_modify_stkvar(rvi_t *value, rfop_t rfop, const insn_t &insn)
1390 {
1391 return reg_finder_may_modify_stkvar(this, value, rfop, &insn);
1392 }
1393
1394private:
1395 // implementation methods
1396 rvi_t find_chain(const flow_t flow, const rfop_t rfop);
1397 void create_initial_block(const flow_t flow, const rfop_t rfop);
1398 // these 2 methods may set ABORTING_EA to abort tracking
1399 bool create_new_block(vref_t *res_vref, const pred_t &pred);
1400 bool handle_block_pred(size_t chain_num, vref_t pred_vref);
1401 vref_t finalize_block();
1402
1403 // for create_new_block()
1404 bool collect_predecessors(qvector<flow_t> *pred_addrs, flow_t flow) const;
1405 bool analyze_linear_flow(
1406 qvector<flow_t> *pred_addrs,
1407 eavec_t *to_eas,
1408 ea_t initial_ea) const;
1409 bool merge_loop_blocks(const block_t *loop_block, sval_t delta);
1410 bool decode_and_emulate_insn(
1411 rvi_t *value,
1412 rfop_t *rfop,
1413 sval_t *delta,
1414 flow_t flow);
1415 bool is_same_func(ea_t ea) const
1416 {
1417 return cur_func != nullptr
1418 ? func_contains(cur_func, ea)
1419 : get_fchunk(ea) == nullptr;
1420 }
1421 rvi_t make_aborted();
1422 bool set_aborted_or_unkinsn(rvi_t *value, const insn_t &insn);
1423
1424 // what to do after move handling?
1425 enum handle_move_res_t
1426 {
1427 HANDLED, // the move is handled, we get a new tracked operand or
1428 // we are sure that it is not spoiled
1429 UNSUPPORTED, // the move does not touch the tracked operand
1430 SPOILED, // a partial modification of the tracked operand is
1431 // detected
1432 };
1433 // handle a move to a tracked register
1434 // \note the operand types should be byte/word/dword/qword.
1435 // \note it may set ABORTING_EA if it returned SPOILED.
1436 // \param [inout] rfop the tracked operand
1437 // \param move_desc the decription of the 'move' insn
1438 // (move_desc_t::delta is not used in this function)
1439 // \param insn the move instruction
1440 handle_move_res_t handle_move(
1441 rfop_t *rfop,
1442 const move_desc_t &move_desc,
1443 const insn_t &insn);
1444
1445 // for SAME the operand widths may be different.
1446 // if it failed to calculate the stkvar offset it returns OVERLAPS.
1447 // \note it may set ABORTING_EA if it returned OVERLAPS.
1448 enum overlap_res_t { SAME, OVERLAPS, DIFFERENT };
1449 overlap_res_t does_rfop_overlap_with_op(
1450 rfop_t rfop,
1451 const op_t &op,
1452 const insn_t &insn);
1453
1454 // it returns success
1455 // \note it may set ABORTING_EA if it returned 'false'.
1456 bool calc_stkvar_off(
1457 sval_t *stkoff,
1458 const op_t &op,
1459 const insn_t &insn,
1460 func_t *pfn);
1461
1462 // to work with chains
1463 reg_value_ud_chain_t &get_chain(size_t chain_num);
1464 const reg_value_ud_chain_t &get_chain(size_t chain_num) const;
1465 void erase_block(size_t chain_num);
1466 // move addresses to the block of TO_CHAIN_NUM adjusting deltas
1467 void move_addrs(
1468 size_t from_chain_num,
1469 size_t to_chain_num,
1470 sval_t delta);
1471 void adjust_deltas(const qvector<addr_t> &addrs, sval_t delta);
1472 void trim_cache(ea_t ea, int max_cache_size);
1473 // does RFOP has at FLOW a value different from CHAIN_NUM?
1474 bool is_rfop_changed(
1475 const flow_t flow,
1476 const rfop_t rfop,
1477 size_t chain_num);
1478
1479 DECLARE_REG_FINDER_HELPERS(friend)
1480
1481 // helper implementation
1482 void invalidate_cache_impl(ea_t to, ea_t from, cref_t cref);
1483 void invalidate_xrefs_cache_impl(ea_t ea, dref_t dref);
1484 rvi_t find_impl(flow_t flow, rfop_t rfop, int max_depth, size_t linear_insns);
1485 rvi_t find_impl2(flow_t flow, rfop_t rfop, int max_depth, size_t linear_insns);
1486 rvi_t find_impl(flow_t flow, const op_t &op);
1487 rvi_t find_impl(flow_t flow, int reg, int max_depth = 0)
1488 {
1489 return find_impl(flow, rfop_t::make_reg(pm, reg), max_depth, 0);
1490 }
1491 rfop_t make_rfop_impl(const op_t &op, const insn_t &insn, func_t *pfn);
1492 bool calc_op_addr_impl(
1493 rvi_t *addr,
1494 const op_t &memop,
1495 const insn_t &insn,
1496 flow_t flow,
1497 int max_depth);
1498 bool emulate_mem_read_impl(
1499 rvi_t *value,
1500 const rvi_t &addr,
1501 int width,
1502 bool is_signed,
1503 const insn_t &insn);
1504 void emulate_binary_op_impl(
1505 rvi_t *value,
1506 rvi_t::arith_op_t aop, // not NEG, NOT
1507 const op_t &op1,
1508 const op_t &op2,
1509 const insn_t &insn,
1510 flow_t flow,
1511 reg_finder_binary_ops_adjust_fun adjust = nullptr,
1512 void *ud = nullptr);
1513 void emulate_unary_op_impl(
1514 rvi_t *value,
1515 rvi_t::arith_op_t aop, // only NEG, NOT
1516 int reg,
1517 const insn_t &insn,
1518 flow_t flow);
1519 bool may_modify_stkvar_impl(
1520 rvi_t *value,
1521 rfop_t rfop,
1522 const insn_t &insn);
1523 bool can_resolve_mem_impl(ea_t ea) const;
1524
1525};
1526
1527//-------------------------------------------------------------------------
1528// convenience functions
1529//-------------------------------------------------------------------------
1540idaman int ida_export find_reg_value(uval_t *uval, ea_t ea, int reg);
1541
1542//-------------------------------------------------------------------------
1554idaman int ida_export find_sp_value(sval_t *sval, ea_t ea, int reg = -1);
1555
1556//-------------------------------------------------------------------------
1578idaman bool ida_export find_reg_value_info(
1579 reg_value_info_t *rvi,
1580 ea_t ea,
1581 int reg,
1582 int max_depth = 0);
1583
1584//-------------------------------------------------------------------------
1593idaman int ida_export find_nearest_rvi(
1594 reg_value_info_t *rvi,
1595 ea_t ea,
1596 const int reg[2]);
1597
1598//-------------------------------------------------------------------------
1603idaman void ida_export invalidate_regfinder_cache(
1604 ea_t to = BADADDR,
1605 ea_t from = BADADDR,
1606 cref_t cref = fl_U);
1607
1608//-------------------------------------------------------------------------
1613 ea_t to = BADADDR,
1614 dref_t dref = dr_O);
1615
1616//-------------------------------------------------------------------------
1617// inline methods
1618//-------------------------------------------------------------------------
1619inline void reg_value_info_t::extend(
1620 const procmod_t &pm,
1621 int width,
1622 bool is_signed)
1623{
1624 if ( !is_known() )
1625 return;
1626 for ( auto &p : vals )
1627 {
1628 p.val = extend_sign(p.val, width, is_signed);
1629 if ( !is_spd() ) // SP delta is signed
1630 p.val = pm.trunc_uval(p.val);
1631 else
1632 p.val = pm.ea2sval(p.val);
1633 }
1634 sort_multivals();
1635}
1636
1637//-------------------------------------------------------------------------
1638inline void reg_value_info_t::trunc_uval(const procmod_t &pm)
1639{
1640 if ( !is_num() )
1641 return;
1642 for ( auto &p : vals )
1643 p.val = pm.trunc_uval(p.val);
1644 sort_multivals();
1645}
1646
1647//-------------------------------------------------------------------------
1648inline bool reg_value_info_t::perform_binary_op(
1649 const reg_value_info_t &r,
1650 arith_op_t aop,
1651 const insn_t &insn)
1652{
1653 const reg_value_info_t *mv;
1654 uint64 sv;
1655 if ( r.is_value_unique() )
1656 {
1657 mv = this;
1658 sv = r.vals.begin()->val;
1659 }
1660 else if ( is_value_unique() )
1661 {
1662 mv = &r;
1663 sv = vals.begin()->val;
1664 }
1665 else
1666 {
1667 return false; // both THIS and R have multiple values
1668 }
1669 qvector<uint64> rvals;
1670 rvals.reserve(mv->vals.size());
1671 for ( const auto &p : mv->vals )
1672 {
1673 uint64 res;
1674 switch ( aop )
1675 {
1676 case ADD: res = p.val + sv; break;
1677 case SUB: res = p.val - sv; break;
1678 case OR: res = p.val | sv; break;
1679 case AND: res = p.val & sv; break;
1680 case XOR: res = p.val ^ sv; break;
1681 case AND_NOT: res = p.val & ~sv; break;
1682 case SLL: res = p.val << sv; break;
1683 case SLR: res = p.val >> sv; break;
1684 case SAR: res = int64(p.val) >> sv; break;
1685 case MOVT: res = (p.val & 0xFFFF) | ((sv & 0xFFFF) << 16); break;
1686 default: return false;
1687 }
1688 rvals.push_back(res);
1689 }
1690 set_multivals(&rvals, insn);
1691 return true;
1692}
1693
1694//-------------------------------------------------------------------------
1695inline void reg_value_info_t::add(
1696 const reg_value_info_t &r,
1697 const insn_t &insn)
1698{
1699 if ( is_spd() && r.is_num() // spd + num -> spd
1700 || is_num() && r.is_spd() // num + spd -> spd
1701 || is_num() && r.is_num() ) // num + num -> num
1702 {
1703 if ( perform_binary_op(r, ADD, insn) )
1704 {
1705 if ( is_spd() || r.is_spd() )
1706 state = SPDINSN;
1707 return;
1708 }
1709 }
1710 // spd + spd or unknown or both THIS and R have multiple values
1711 set_unkinsn(insn);
1712}
1713
1714//-------------------------------------------------------------------------
1715inline void reg_value_info_t::sub(
1716 const reg_value_info_t &r,
1717 const insn_t &insn)
1718{
1719 if ( is_spd() && r.is_num() // spd - num -> spd
1720 || is_spd() && r.is_spd() // spd - spd -> num
1721 || is_num() && r.is_num() ) // num - num -> num
1722 {
1723 if ( perform_binary_op(r, SUB, insn) )
1724 {
1725 if ( is_spd() )
1726 state = r.is_spd() ? NUMINSN : SPDINSN;
1727 return;
1728 }
1729 }
1730 // num - spd or unknown or both THIS and R have multiple values
1731 set_unkinsn(insn);
1732}
1733
1734//-------------------------------------------------------------------------
1735inline void reg_value_info_t::bor(
1736 const reg_value_info_t &r,
1737 const insn_t &insn)
1738{
1739 if ( is_num() && r.is_num() )
1740 if ( perform_binary_op(r, OR, insn) )
1741 return;
1742 // not numbers or both THIS and R have multiple values
1743 set_unkinsn(insn);
1744}
1745
1746//-------------------------------------------------------------------------
1747inline void reg_value_info_t::band(
1748 const reg_value_info_t &r,
1749 const insn_t &insn)
1750{
1751 uval_t mask;
1752 if ( is_spd() && r.get_num(&mask) && is_pow2(mask + 1) && mask <= 31 )
1753 {
1754 if ( perform_binary_op(r, AND, insn) )
1755 {
1756 state = NUMINSN;
1757 return;
1758 }
1759 }
1760 if ( is_num() && r.is_num() )
1761 {
1762 if ( perform_binary_op(r, AND, insn) )
1763 return;
1764 }
1765 // not numbers or not mask of SPD or both THIS and R have multiple values
1766 set_unkinsn(insn);
1767}
1768
1769//-------------------------------------------------------------------------
1770inline void reg_value_info_t::bxor(
1771 const reg_value_info_t &r,
1772 const insn_t &insn)
1773{
1774 if ( is_num() && r.is_num() )
1775 if ( perform_binary_op(r, XOR, insn) )
1776 return;
1777 // not numbers or both THIS and R have multiple values
1778 set_unkinsn(insn);
1779}
1780
1781//-------------------------------------------------------------------------
1782inline void reg_value_info_t::bandnot(
1783 const reg_value_info_t &r,
1784 const insn_t &insn)
1785{
1786 uval_t mask;
1787 if ( is_spd() && r.get_num(&mask) && is_pow2(mask + 1) && mask <= 31 )
1788 if ( perform_binary_op(r, AND_NOT, insn) )
1789 return;
1790 if ( is_num() && r.is_num() )
1791 if ( perform_binary_op(r, AND_NOT, insn) )
1792 return;
1793 // not numbers or not SPD aligning or both THIS and R have multiple values
1794 set_unkinsn(insn);
1795}
1796
1797//-------------------------------------------------------------------------
1798inline void reg_value_info_t::sll(
1799 const reg_value_info_t &r,
1800 const insn_t &insn)
1801{
1802 if ( is_num() && r.is_num() && perform_binary_op(r, SLL, insn) )
1803 ;
1804 else // not numbers
1805 set_unkinsn(insn);
1806}
1807
1808//-------------------------------------------------------------------------
1809inline void reg_value_info_t::slr(
1810 const reg_value_info_t &r,
1811 const insn_t &insn)
1812{
1813 if ( is_num() && r.is_num() && perform_binary_op(r, SLR, insn) )
1814 ;
1815 else // not numbers
1816 set_unkinsn(insn);
1817}
1818
1819//-------------------------------------------------------------------------
1820inline void reg_value_info_t::sar(
1821 const reg_value_info_t &r,
1822 const insn_t &insn)
1823{
1824 if ( is_num() && r.is_num() && perform_binary_op(r, SAR, insn) )
1825 ;
1826 else // not numbers
1827 set_unkinsn(insn);
1828}
1829
1830//-------------------------------------------------------------------------
1831inline void reg_value_info_t::movt(
1832 const reg_value_info_t &r,
1833 const insn_t &insn)
1834{
1835 if ( is_num() && r.is_num() && perform_binary_op(r, MOVT, insn) )
1836 ;
1837 else // not numbers
1838 set_unkinsn(insn);
1839}
1840
1841//-------------------------------------------------------------------------
1842inline void reg_value_info_t::neg(const insn_t &insn)
1843{
1844 if ( is_num() )
1845 {
1846 qvector<uint64> rvals;
1847 rvals.reserve(vals.size());
1848 for ( auto &p : vals )
1849 rvals.push_back(0-p.val);
1850 set_multivals(&rvals, insn);
1851 }
1852 else // not a number
1853 {
1854 set_unkinsn(insn);
1855 }
1856}
1857
1858//-------------------------------------------------------------------------
1859inline void reg_value_info_t::bnot(const insn_t &insn)
1860{
1861 if ( is_num() )
1862 {
1863 qvector<uint64> rvals;
1864 rvals.reserve(vals.size());
1865 for ( auto &p : vals )
1866 rvals.push_back(~p.val);
1867 set_multivals(&rvals, insn);
1868 }
1869 else // not a number
1870 {
1871 set_unkinsn(insn);
1872 }
1873}
1874
1875//-------------------------------------------------------------------------
1876inline void reg_value_info_t::add_num(uval_t r, const insn_t &insn)
1877{
1878 if ( !is_known() || r == 0 )
1879 return;
1880 qvector<uint64> rvals;
1881 rvals.reserve(vals.size());
1882 for ( auto &p : vals )
1883 rvals.push_back(p.val + r);
1884 set_multivals(&rvals, insn);
1885}
1886
1887//-------------------------------------------------------------------------
1888inline void reg_value_info_t::add_num(uval_t r)
1889{
1890 if ( !is_known() || r == 0 )
1891 return;
1892 for ( auto &p : vals )
1893 p.val += r;
1894 sort_multivals();
1895}
1896
1897//-------------------------------------------------------------------------
1898inline void reg_value_info_t::shift_left(uval_t r)
1899{
1900 if ( !is_known() || r == 0 )
1901 return;
1902 for ( auto &p : vals )
1903 p.val <<= r;
1904 sort_multivals();
1905}
1906
1907//-------------------------------------------------------------------------
1908inline void reg_value_info_t::shift_right(uval_t r)
1909{
1910 if ( !is_known() || r == 0 )
1911 return;
1912 for ( auto &p : vals )
1913 p.val >>= r;
1914 sort_multivals();
1915}
1916
1917//-------------------------------------------------------------------------
1918template<class V>
1919inline void reg_value_info_t::set_multivals(
1920 V *rvals,
1921 const insn_t &insn)
1922{
1923 // DEF_EA will be the same so it is enough to sort only VAL
1924 std::sort(rvals->begin(), rvals->end());
1925 size_t newsz = std::unique(rvals->begin(), rvals->end()) - rvals->begin();
1926 vals.resize(newsz);
1927 for ( size_t i = 0; i < newsz; ++i )
1928 vals[i] = val_def_t(rvals->at(i), insn);
1929}
1930
1931//-------------------------------------------------------------------------
1932inline void reg_value_info_t::sort_multivals()
1933{
1934 // at this point we use reg_value_def_t::operator<()
1935 std::sort(vals.begin(), vals.end());
1936 // at this point we use reg_value_def_t::operator==()
1937 size_t new_size = std::unique(vals.begin(), vals.end()) - vals.begin();
1938 vals.resize(new_size);
1939}
1940
1941//-------------------------------------------------------------------------
1942inline reg_finder_op_t reg_finder_op_t::make_reg(int reg, int width)
1943{
1944 uint32 packed_width = pack_width(width);
1945 if ( packed_width == BADREG || !is_valid_reg(reg) )
1946 return rfop_t();
1947 return rfop_t(REG | packed_width | uint16(reg));
1948}
1949
1950//-------------------------------------------------------------------------
1951inline reg_finder_op_t reg_finder_op_t::make_stkoff(
1952 sval_t stkoff,
1953 int width)
1954{
1955 uint32 packed_width = pack_width(width);
1956 if ( packed_width == BADREG || !is_valid_stkoff(stkoff) )
1957 return rfop_t();
1958 bool negative = stkoff < 0;
1959 return rfop_t(STKVAR
1960 | packed_width
1961 | (negative ? STKOFF_SIGNBIT : 0)
1962 | uint32(negative ? -stkoff : stkoff));
1963}
1964
1965//-------------------------------------------------------------------------
1966inline void reg_finder_op_t::set_width(int width)
1967{
1968 uint32 packed_width = pack_width(width);
1969 if ( packed_width == BADREG )
1970 {
1971 clear();
1972 return;
1973 }
1974 packed &= ~WIDTH_MASK;
1975 packed |= packed_width;
1976}
1977
1978//-------------------------------------------------------------------------
1980{
1981 packed &= ~SIGNED;
1982 if ( is_signed )
1983 packed |= SIGNED;
1984}
1985
1986//-------------------------------------------------------------------------
1988{
1989 uint32 packed_width = pack_width(width);
1990 if ( packed_width == BADREG )
1991 {
1992 clear();
1993 return;
1994 }
1995 packed &= ~WIDTH_MASK;
1996 packed |= packed_width;
1997 packed &= ~SIGNED;
1998 if ( is_signed )
1999 packed |= SIGNED;
2000}
2001
2002//-------------------------------------------------------------------------
2004{
2005 switch ( width )
2006 {
2007 case 1: return 0 << WIDTH_SHIFT; break;
2008 case 2: return 1 << WIDTH_SHIFT; break;
2009 case 4: return 2 << WIDTH_SHIFT; break;
2010 case 8: return 3 << WIDTH_SHIFT; break;
2011 default: return BADREG;
2012 }
2013}
2014
2015//-------------------------------------------------------------------------
2017{
2018 return get_dtype_size(op.dtype);
2019}
A function is a set of continuous ranges of addresses with characteristics.
Definition funcs.hpp:85
Operand of an instruction.
Definition ua.hpp:170
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
void reserve(size_t cnt)
Increase the capacity of the qvector.
Definition pro.h:2528
void swap(qvector< T > &r) noexcept
Replace all attributes of this qvector with that of 'r', and vice versa.
Definition pro.h:2560
void qclear(void)
Destroy all elements but do not free memory.
Definition pro.h:2434
iterator end(void)
Get an iterator that points to the end of the qvector (NOT the last element)
Definition pro.h:2610
iterator begin(void)
Get an iterator that points to the first element in the qvector.
Definition pro.h:2609
void push_back(T &&x)
Append a new element to the end the qvector with a move semantics.
Definition pro.h:2361
size_t size(void) const
Get the number of elements in the qvector.
Definition pro.h:2423
idaman sval_t ida_export get_spd(func_t *pfn, ea_t ea)
Get difference between the initial and current values of ESP.
bool func_contains(func_t *pfn, ea_t ea)
Does the given function contain the given address?
Definition funcs.hpp:305
idaman func_t *ida_export get_fchunk(ea_t ea)
Get pointer to function chunk structure by address.
bool is_same_func(ea_t ea1, ea_t ea2)
Do two addresses belong to the same function?
Definition funcs.hpp:311
THREAD_SAFE constexpr bool idaapi is_unknown(flags64_t F)
Does flag denote unexplored byte?
Definition bytes.hpp:805
const optype_t o_imm
An immediate Value (constant).
Definition ua.hpp:92
const optype_t o_void
No Operand.
Definition ua.hpp:82
int code
Definition fpro.h:88
const char *hexapi dstr(const tinfo_t *tif)
Print the specified type info.
Definition hexrays.hpp:10432
cref_t
CODE xref types.
Definition xref.hpp:49
dref_t
DATA xref types.
Definition xref.hpp:67
@ fl_U
unknown – for compatibility with old versions.
Definition xref.hpp:50
@ dr_O
Offset The reference uses 'offset' of data rather than its value OR The reference appeared because th...
Definition xref.hpp:70
cexpr_t *hexapi make_num(uint64 n, cfunc_t *func=nullptr, ea_t ea=BADADDR, int opnum=0, type_sign_t sign=no_sign, int size=0)
Create a number expression.
Definition hexrays.hpp:12657
Contains definition of the interface to IDP modules.
uval_t uval_t
Definition kernwin.hpp:1878
void(idaapi *range_marker)(ea_t ea
Pointer to range marker function (for idaviews and hexviews) This pointer is initialized by setup_ran...
unsigned __int64 uint64
Definition llong.hpp:13
__int64 int64
Definition llong.hpp:14
This is the first header included in the IDA project.
unsigned short uint16
unsigned 16 bit value
Definition pro.h:346
unsigned int uint32
unsigned 32 bit value
Definition pro.h:348
qvector< uval_t > uvalvec_t
vector of unsigned values
Definition pro.h:2762
adiff_t sval_t
signed value used by the processor.
Definition pro.h:446
uint64 ea_t
Definition pro.h:421
int int32
signed 32 bit value
Definition pro.h:347
unsigned char uchar
unsigned 8 bit value
Definition pro.h:337
THREAD_SAFE void qswap(T &a, T &b)
Swap 2 objects of the same type using memory copies.
Definition pro.h:1715
qvector< ea_t > eavec_t
vector of addresses
Definition pro.h:2764
idaman uint64 ida_export extend_sign(uint64 v, int nbytes, bool sign_extend)
Sign-, or zero-extend the value 'v' to occupy 64 bits.
unsigned char uint8
unsigned 8 bit value
Definition pro.h:344
constexpr bool is_pow2(T val)
is power of 2? (or zero)
Definition pro.h:1432
_qstring< char > qstring
regular string
Definition pro.h:3694
int compare(const T &a, const T &b)
Definition pro.h:4514
idaman bool ida_export find_reg_value_info(reg_value_info_t *rvi, ea_t ea, int reg, int max_depth=0)
Find register value using the register tracker.
idaman int ida_export find_reg_value(uval_t *uval, ea_t ea, int reg)
Find register value using the register tracker.
idaman void ida_export invalidate_regfinder_cache(ea_t to=BADADDR, ea_t from=BADADDR, cref_t cref=fl_U)
The control flow from FROM to TO has removed (CREF==fl_U) or added (CREF!=fl_U).
void(* reg_finder_binary_ops_adjust_fun)(reg_value_info_t *v1, reg_value_info_t *v2, const insn_t &insn, void *ud)
Definition regfinder.hpp:794
idaman int ida_export find_sp_value(sval_t *sval, ea_t ea, int reg=-1)
Find a value of the SP based register using the register tracker.
DECLARE_REG_VALUE_INFO_HELPERS(idaman) struct reg_value_info_t
the value in a register after emulating instructions
Definition regfinder.hpp:136
DECLARE_REG_VALUE_DEF_HELPERS(idaman) struct reg_value_def_t
the register value and its defining instruction
Definition regfinder.hpp:56
DECLARE_TYPE_AS_MOVABLE(reg_value_def_t)
idaman void ida_export invalidate_regfinder_xrefs_cache(ea_t to=BADADDR, dref_t dref=dr_O)
The data reference to TO has added (DREF!=dr_O) or removed (DREF==dr_O).
DECLARE_REG_FINDER_HELPERS(idaman) struct reg_finder_block_t
idaman int ida_export find_nearest_rvi(reg_value_info_t *rvi, ea_t ea, const int reg[2])
Find the value of any of the two registers using the register tracker.
Definition idp.hpp:2085
Definition regfinder.hpp:703
void set_width_signness(int width, bool is_signed)
Definition regfinder.hpp:1987
rfop_t & operator=(const rfop_t &r)=default
bool empty() const
Definition regfinder.hpp:735
void set_width(int width)
Definition regfinder.hpp:1966
static bool is_valid_reg(int reg)
Definition regfinder.hpp:738
uint16 get_reg() const
Definition regfinder.hpp:767
void set_signness(bool is_signed)
Definition regfinder.hpp:1979
reg_finder_op_t(const rfop_t &r)=default
void clear()
Definition regfinder.hpp:736
reg_finder_op_t()
Definition regfinder.hpp:729
static reg_finder_op_t make_reg(int reg, int width)
Definition regfinder.hpp:1942
static bool is_valid_stkoff(sval_t stkoff)
Definition regfinder.hpp:748
int get_width() const
Definition regfinder.hpp:762
static reg_finder_op_t make_reg(const procmod_t &pm, int reg)
Definition regfinder.hpp:743
static reg_finder_op_t make_stkoff(sval_t stkoff, int width)
Definition regfinder.hpp:1951
reg_finder_op_t rfop_t
Definition regfinder.hpp:728
static uint32 pack_width(int width)
Definition regfinder.hpp:2003
bool is_reg() const
Definition regfinder.hpp:759
sval_t get_stkoff() const
Definition regfinder.hpp:768
DECLARE_COMPARISONS(reg_finder_op_t)
Definition regfinder.hpp:776
bool is_signed() const
Definition regfinder.hpp:761
static int get_op_width(const op_t &op)
Definition regfinder.hpp:2016
bool is_stkvar() const
Definition regfinder.hpp:760
bool is_reg(int reg) const
Definition regfinder.hpp:774
Definition regfinder.hpp:877
cond_t(uchar cond=AL, uchar kind=NONE)
Definition regfinder.hpp:913
uchar get_kind() const
Definition regfinder.hpp:929
@ JUMPS
Definition regfinder.hpp:910
@ NONE
Definition regfinder.hpp:908
@ MODIFIES_CC
Definition regfinder.hpp:909
bool jumps() const
Definition regfinder.hpp:934
@ LE
Definition regfinder.hpp:901
@ VC
Definition regfinder.hpp:895
@ NV
Definition regfinder.hpp:903
@ AL
Definition regfinder.hpp:902
@ CC
Definition regfinder.hpp:891
@ HI
Definition regfinder.hpp:896
@ EQ
Definition regfinder.hpp:888
@ CS
Definition regfinder.hpp:890
@ LS
Definition regfinder.hpp:897
@ MI
Definition regfinder.hpp:892
@ LT
Definition regfinder.hpp:899
@ PL
Definition regfinder.hpp:893
@ VS
Definition regfinder.hpp:894
@ GE
Definition regfinder.hpp:898
@ NE
Definition regfinder.hpp:889
@ GT
Definition regfinder.hpp:900
bool modifies_cond_codes() const
Definition regfinder.hpp:933
uchar get_cond() const
Definition regfinder.hpp:916
bool is_included_in(cond_t r) const
Definition regfinder.hpp:920
Definition regfinder.hpp:1165
void handle_delay_slot()
Definition regfinder.hpp:1172
bool has_delay_slot() const
Definition regfinder.hpp:1168
bool operator<(const flow_t &r) const
Definition regfinder.hpp:1185
ea_t ds
Definition regfinder.hpp:1167
flow_t(ea_t _ea, ea_t _ds=BADADDR)
Definition regfinder.hpp:1174
ea_t ea
Definition regfinder.hpp:1166
bool is_ea_handled() const
Definition regfinder.hpp:1170
ea_t actual_ea() const
Definition regfinder.hpp:1182
Definition regfinder.hpp:1258
bool is_signed
Definition regfinder.hpp:1272
sval_t delta
Definition regfinder.hpp:1278
const op_t * src_op
Definition regfinder.hpp:1269
rfop_t new_rfop
Definition regfinder.hpp:1261
const op_t * dst_op
Definition regfinder.hpp:1267
Definition regfinder.hpp:821
bool does_call_spoil_stkvars() const
Definition regfinder.hpp:836
rvi_t find(flow_t flow, rfop_t rfop)
Definition regfinder.hpp:1327
const procmod_t & pm
Definition regfinder.hpp:822
virtual cond_t get_cond(ea_t ea) const
Definition regfinder.hpp:1205
rvi_t find_op_addr(const op_t &memop, const insn_t &insn, int max_depth=0)
Definition regfinder.hpp:1119
size_t linear_flow_cnt
Definition regfinder.hpp:860
reg_value_info_t rvi_t
Definition regfinder.hpp:846
virtual bool is_funcwide_reg(ea_t ea, int reg) const
Definition regfinder.hpp:1242
friend struct reg_finder_chainvec_t
Definition regfinder.hpp:940
friend struct reg_finder_block_t
Definition regfinder.hpp:850
friend struct reg_finder_pred_t
Definition regfinder.hpp:851
reg_finder_block_t block_t
Definition regfinder.hpp:848
friend struct reg_finder_xrefs_cache_t
Definition regfinder.hpp:985
reg_finder_t(const procmod_t &_pm, int _proc_maxop=3, uint32 _flags=RF_DOES_CALL_SPOIL_STKVARS)
Definition regfinder.hpp:992
size_t bblk_cnt
Definition regfinder.hpp:863
virtual int get_sp_reg(ea_t ea) const
Definition regfinder.hpp:1235
void emulate_binary_op(rvi_t *value, rvi_t::arith_op_t aop, const op_t &op1, const op_t &op2, const insn_t &insn, flow_t flow, reg_finder_binary_ops_adjust_fun adjust=nullptr, void *ud=nullptr)
Definition regfinder.hpp:1358
virtual bool can_track_op(op_t *op, const insn_t &insn, func_t *pfn) const
Definition regfinder.hpp:1248
int find_nearest(reg_value_info_t *rvi, ea_t ea, const int reg[2], size_t linear_insns=10)
Definition regfinder.hpp:1054
static constexpr uint32 RF_ALLOW_XREFS_CACHE
Definition regfinder.hpp:834
ea_t aborting_ea
Definition regfinder.hpp:864
op_t fake_op1
Definition regfinder.hpp:871
bool can_resolve_mem(ea_t ea) const
Definition regfinder.hpp:1155
const int proc_maxop
Definition regfinder.hpp:823
bool may_modify_stkvar(rvi_t *value, rfop_t rfop, const insn_t &insn)
Definition regfinder.hpp:1389
rvi_t standalone_value
Definition regfinder.hpp:865
virtual bool emulate_insn(rvi_t *value, const rfop_t &rfop, const insn_t &insn, flow_t flow)
Definition regfinder.hpp:1310
uint32 flags
Definition regfinder.hpp:825
void calc_op_addr(rvi_t *addr, const op_t &memop, const insn_t &insn, flow_t flow)
Definition regfinder.hpp:1347
virtual bool is_mem_readonly(ea_t) const
Definition regfinder.hpp:1229
virtual flow_t process_delay_slot(ea_t ea, cref_t) const
Definition regfinder.hpp:1199
void invalidate_cache()
Definition regfinder.hpp:1012
virtual rvi_t handle_well_known_regs(flow_t flow, rfop_t rfop, bool is_func_start) const
Definition regfinder.hpp:1215
bool only_linear_flow() const
Definition regfinder.hpp:862
size_t initial_block_idx
Definition regfinder.hpp:855
static constexpr size_t NO_CHAIN
Definition regfinder.hpp:868
friend struct reg_finder_rfop_chains_t
Definition regfinder.hpp:976
reg_finder_op_t rfop_t
Definition regfinder.hpp:847
rvi_t find(flow_t flow, int reg)
Definition regfinder.hpp:1337
void invalidate_xrefs_cache(ea_t ea, dref_t dref)
Definition regfinder.hpp:1019
virtual ~reg_finder_t()
Definition regfinder.hpp:1002
bool fixed_max_depth
Definition regfinder.hpp:856
func_t * cur_func
Definition regfinder.hpp:854
void emulate_mem_read(rvi_t *value, const rvi_t &addr, int width, bool is_signed, const insn_t &insn)
Definition regfinder.hpp:1142
static constexpr uint32 RF_DOES_CALL_SPOIL_STKVARS
Definition regfinder.hpp:829
rfop_t make_rfop(const op_t &_op, const insn_t &insn, func_t *pfn)
Definition regfinder.hpp:1098
void emulate_unary_op(rvi_t *value, rvi_t::arith_op_t aop, int reg, const insn_t &insn, flow_t flow)
Definition regfinder.hpp:1373
bool allow_xrefs_cache() const
Definition regfinder.hpp:840
bool find_spd(sval_t *spval, ea_t ea, int reg=-1, int max_depth=-1)
Definition regfinder.hpp:1085
int cur_call_depth
Definition regfinder.hpp:859
void invalidate_cache(ea_t to, ea_t from, cref_t cref)
Definition regfinder.hpp:1007
int cur_max_depth
Definition regfinder.hpp:858
rvi_t find(ea_t ea, rfop_t rfop, int max_depth=0, size_t linear_insns=0)
Definition regfinder.hpp:1039
bool find_const(uval_t *val, ea_t ea, rfop_t rfop, int max_depth=0)
Definition regfinder.hpp:1078
virtual bool is_move_insn(move_desc_t *move_desc, const rfop_t &rfop, const insn_t &insn)
Definition regfinder.hpp:1285
op_t fake_op2
Definition regfinder.hpp:872
reg_finder_pred_t pred_t
Definition regfinder.hpp:849
THREAD_SAFE bool operator<(const bytevec_t &v1, const bytevec_t &v2)
Compare two bytevecs with '<'.
Definition typeinf.hpp:631
Functions that deal with the disassembling of program instructions.
idaman size_t ida_export get_dtype_size(op_dtype_t dtype)
Get size of opt_::dtype field.