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-2026 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_base_t;
132#define DECLARE_REG_VALUE_BASE_HELPERS(decl)\
133decl int ida_export reg_value_base_vals_union(reg_value_base_t *_this, const reg_value_base_t *r);\
134decl void ida_export reg_value_base_dstr(const reg_value_base_t *_this, qstring *vout, const procmod_t *pm);
135
137
138//-------------------------------------------------------------------------
140struct reg_value_base_t
141{
142protected:
143 using val_def_t = reg_value_def_t;
144 friend struct reg_finder_block_t; // for join_values()
145 friend struct reg_value_info_t; // for derived class access
146 friend struct reg_value_info93_t; // 9.3 ABI shim: needs raw vals/state
147
148 enum state_t : uint8
149 {
150 UNDEF, // we know nothing about a value
151 DEADEND, // no execution flow to the insn
152 ABORTED, // the tracking process was aborted because the maximal
153 // tracking depth is not enough to find a value or it found
154 // the huge basic block
155 BADINSN, // the insn cannot be decoded
156 UNKINSN, // the result of the insn execution is unknown
157 UNKFUNC, // the register comes from the function start
158 UNKLOOP, // the register is changed in a loop
159 UNKMULT, // the register has incompatible values
160 // (a number and SP delta)
161 UNKXREF, // too many xrefs to the address
162 UNKVALS, // the register has too many values at the address
163 NUMINSN, // the value is a number after executing the insn
164 NUMADDR, // the value is a number before the address
165 SPDINSN, // the value is a SP delta after executing the insn
166 SPDADDR, // the value is a SP delta before the address
167 };
168 // the SP delta is the value of SP minus the initial value of SP at the
169 // function start.
170 // each value (except UNDEF) may be set either before or after executing
171 // an insn at vals[i].def_ea. in the table below, these options are
172 // labeled B and A, respectively. The table shows what address is in
173 // vals[i].def_ea.
174 // the states below allow a single value
175 // DEADEND B the address of the dead end
176 // ABORTED B the address where it was aborted
177 // BADINSN A the insn address (ITYPE is not set)
178 // UNKINSN A the insn address
179 // UNKFUNC B the function start address
180 // UNKLOOP B the address of the changing insn
181 // UNKMULT B the address of the joint point
182 // UNKXREF B the address with a lot of xrefs
183 // UNKVALS B the address with a lot of values
184 // the states below allow multiple values
185 // NUMINSN A the address of the defining insn
186 // NUMADDR B the address after which the value became known
187 // SPDINSN A the address of the defining insn
188 // SPDADDR B the address after which the value became known
189
190 qvector<val_def_t> vals; // sorted
191 state_t state = UNDEF; // state of the value being tracked
192
193 explicit reg_value_base_t(
194 state_t _state,
195 ea_t def_ea,
196 uint64 _val = BADADDR,
197 uint16 val_flags = 0)
198 : state(_state)
199 {
200 vals.push_back(val_def_t(_val, def_ea, val_flags));
201 }
202 explicit reg_value_base_t(
203 state_t _state,
204 const insn_t &insn,
205 uint64 _val = BADADDR,
206 uint16 val_flags = 0)
207 : state(_state)
208 {
209 vals.push_back(val_def_t(_val, insn, val_flags));
210 }
211
212public:
213 reg_value_base_t() {}
215 void clear()
216 {
217 state = UNDEF;
218 vals.qclear();
219 }
221 bool empty() const { return state == UNDEF; }
222
223 void swap(reg_value_base_t &r) noexcept
224 {
225 std::swap(state, r.state);
226 vals.swap(r.vals);
227 }
228
231 static reg_value_base_t make_dead_end(ea_t dead_end_ea)
232 {
233 return reg_value_base_t(DEADEND, dead_end_ea);
234 }
235
238 static reg_value_base_t make_aborted(
239 ea_t bblk_ea,
240 int aborting_depth = -1)
241 {
242 return reg_value_base_t(ABORTED, bblk_ea, uint32(aborting_depth));
243 }
244
247 static reg_value_base_t make_badinsn(ea_t insn_ea)
248 {
249 return reg_value_base_t(BADINSN, insn_ea);
250 }
251
254 static reg_value_base_t make_unkinsn(const insn_t &insn)
255 {
256 return reg_value_base_t(UNKINSN, insn);
257 }
258
261 static reg_value_base_t make_unkfunc(ea_t func_ea)
262 {
263 return reg_value_base_t(UNKFUNC, func_ea);
264 }
265
268 static reg_value_base_t make_unkloop(ea_t bblk_ea)
269 {
270 return reg_value_base_t(UNKLOOP, bblk_ea);
271 }
272
275 static reg_value_base_t make_unkmult(ea_t bblk_ea)
276 {
277 return reg_value_base_t(UNKMULT, bblk_ea);
278 }
279
282 static reg_value_base_t make_unkxref(ea_t bblk_ea)
283 {
284 return reg_value_base_t(UNKXREF, bblk_ea);
285 }
286
289 static reg_value_base_t make_unkvals(ea_t bblk_ea)
290 {
291 return reg_value_base_t(UNKVALS, bblk_ea);
292 }
293
296 static reg_value_base_t make_num(
297 uint64 rval,
298 const insn_t &insn,
299 uint16 val_flags = 0)
300 {
301 return reg_value_base_t(NUMINSN, insn, rval, val_flags);
302 }
305 static reg_value_base_t make_num(
306 uint64 rval,
307 ea_t val_ea,
308 uint16 val_flags = 0)
309 {
310 return reg_value_base_t(NUMADDR, val_ea, rval, val_flags);
311 }
312
315 static reg_value_base_t make_initial_sp(ea_t func_ea)
316 {
317 return reg_value_base_t(SPDADDR, func_ea, 0);
318 }
319
320 //-----------------------------------------------------------------------
321 // access methods
322
324 bool is_dead_end() const { return state == DEADEND; }
326 bool aborted() const { return state == ABORTED; }
328 bool is_special() const { return is_dead_end() || aborted(); }
329
331 bool is_badinsn() const { return state == BADINSN; }
333 bool is_unkinsn() const { return state == UNKINSN; }
335 bool is_unkfunc() const { return state == UNKFUNC; }
337 bool is_unkloop() const { return state == UNKLOOP; }
340 bool is_unkmult() const { return state == UNKMULT; }
342 bool is_unkxref() const { return state == UNKXREF; }
345 bool is_unkvals() const { return state == UNKVALS; }
347 bool is_unknown() const
348 {
349 return state == BADINSN
350 || state == UNKINSN
351 || state == UNKFUNC
352 || state == UNKLOOP
353 || state == UNKMULT
354 || state == UNKXREF
355 || state == UNKVALS;
356 }
357
359 bool is_num() const { return state == NUMINSN || state == NUMADDR; }
361 bool is_spd() const { return state == SPDINSN || state == SPDADDR; }
363 bool is_known() const { return is_num() || is_spd(); }
364
366 ea_t get_def_ea() const
367 {
368 return vals.size() != 1 ? BADADDR : vals.begin()->def_ea;
369 }
371 uint16 get_def_itype() const
372 {
373 return vals.size() != 1 ? 0 : vals.begin()->def_itype;
374 }
376 int get_aborting_depth() const
377 {
378 if ( !aborted() || vals.size() != 1 )
379 return -1;
380 return int32(vals.begin()->val);
381 }
386 bool set_def_itype_for_mov(const insn_t &insn)
387 {
388 if ( vals.size() != 1
389 || vals.begin()->def_ea != insn.ea
390 || vals.begin()->def_itype != 0 )
391 {
392 return false;
393 }
394 if ( state == NUMADDR )
395 state = NUMINSN;
396 else if ( state == SPDADDR )
397 state = SPDINSN;
398 else
399 return false;
400 vals.begin()->def_itype = insn.itype;
401 return true;
402 }
403
405 const reg_value_def_t *vals_begin() const { return vals.begin(); }
407 const reg_value_def_t *vals_end() const { return vals.end(); }
409 size_t vals_size() const { return vals.size(); }
410
412 bool is_value_unique() const
413 {
414 if ( empty() )
415 return false;
416 if ( vals.size() == 1 )
417 return true;
418 auto p = vals.begin();
419 uint64 v = p->val;
420 for ( ++p; p != vals.end(); ++p )
421 if ( p->val != v )
422 return false;
423 return true;
424 }
425
427 bool have_all_vals_flag(uint16 val_flags) const
428 {
429 for ( auto p : vals )
430 if ( (p.flags & val_flags) == 0 )
431 return false;
432 return true;
433 }
434 bool has_any_vals_flag(uint16 val_flags) const
435 {
436 for ( auto p : vals )
437 if ( (p.flags & val_flags) != 0 )
438 return true;
439 return false;
440 }
441 bool is_all_vals_pc_based() const
442 {
443 return have_all_vals_flag(val_def_t::PC_BASED);
444 }
445 bool is_any_vals_pc_based() const
446 {
447 return has_any_vals_flag(val_def_t::PC_BASED);
448 }
449 bool is_all_vals_like_got() const
450 {
451 return have_all_vals_flag(val_def_t::LIKE_GOT);
452 }
453 bool is_any_vals_like_got() const
454 {
455 return has_any_vals_flag(val_def_t::LIKE_GOT);
456 }
457
459 void set_all_vals_flag(uint16 val_flags)
460 {
461 for ( auto &p : vals )
462 p.flags |= val_flags;
463 }
464 void set_all_vals_pc_based()
465 {
466 return set_all_vals_flag(val_def_t::PC_BASED);
467 }
468 void set_all_vals_got_based()
469 {
470 return set_all_vals_flag(val_def_t::LIKE_GOT);
471 }
472
473 //-----------------------------------------------------------------------
474 // modification methods
475
478 void set_dead_end(ea_t dead_end_ea)
479 {
480 state = DEADEND;
481 vals.qclear();
482 vals.push_back(val_def_t(BADADDR, dead_end_ea));
483 }
484
487 void set_badinsn(ea_t insn_ea)
488 {
489 state = BADINSN;
490 vals.qclear();
491 vals.push_back(val_def_t(BADADDR, insn_ea));
492 }
493
496 void set_unkinsn(const insn_t &insn)
497 {
498 state = UNKINSN;
499 vals.qclear();
500 vals.push_back(val_def_t(BADADDR, insn));
501 }
502
505 void set_unkfunc(ea_t func_ea)
506 {
507 state = UNKFUNC;
508 vals.qclear();
509 vals.push_back(val_def_t(BADADDR, func_ea));
510 }
511
514 void set_unkloop(ea_t bblk_ea)
515 {
516 state = UNKLOOP;
517 vals.qclear();
518 vals.push_back(val_def_t(BADADDR, bblk_ea));
519 }
520
523 void set_unkmult(ea_t bblk_ea)
524 {
525 state = UNKMULT;
526 vals.qclear();
527 vals.push_back(val_def_t(BADADDR, bblk_ea));
528 }
529
532 void set_unkxref(ea_t bblk_ea)
533 {
534 state = UNKXREF;
535 vals.qclear();
536 vals.push_back(val_def_t(BADADDR, bblk_ea));
537 }
538
541 void set_unkvals(ea_t bblk_ea)
542 {
543 state = UNKVALS;
544 vals.qclear();
545 vals.push_back(val_def_t(BADADDR, bblk_ea));
546 }
547
550 void set_aborted(ea_t bblk_ea, int aborting_depth = -1)
551 {
552 state = ABORTED;
553 vals.qclear();
554 vals.push_back(val_def_t(uint32(aborting_depth), bblk_ea));
555 }
556
559 void set_num(uint64 rval, const insn_t &insn, uint16 val_flags = 0)
560 {
561 state = NUMINSN;
562 vals.qclear();
563 vals.push_back(val_def_t(rval, insn, val_flags));
564 }
568 void set_num(uvalvec_t *rvals, const insn_t &insn)
569 {
570 set_multivals(rvals, insn);
571 state = NUMINSN;
572 }
575 void set_num(uint64 rval, ea_t val_ea, uint16 val_flags = 0)
576 {
577 state = NUMADDR;
578 vals.qclear();
579 vals.push_back(val_def_t(rval, val_ea, val_flags));
580 }
581
583 enum set_compare_res_t
584 {
585 EQUAL,
586 CONTAINS,
587 CONTAINED,
588 NOT_COMPARABLE,
589 };
596 set_compare_res_t vals_union(const reg_value_base_t &r)
597 {
598 return set_compare_res_t(reg_value_base_vals_union(this, &r));
599 }
600
601 // arithmetic operations
602 enum arith_op_t
603 {
604 ADD, SUB,
605 OR, AND, XOR, AND_NOT,
606 SLL, SLR, SAR, MOVT,
607 NEG, NOT,
608 };
609
613 inline void add(const reg_value_base_t &r, const insn_t &insn);
616 inline void sub(const reg_value_base_t &r, const insn_t &insn);
619 inline void bor(const reg_value_base_t &r, const insn_t &insn);
622 inline void band(const reg_value_base_t &r, const insn_t &insn);
625 inline void bxor(const reg_value_base_t &r, const insn_t &insn);
628 inline void bandnot(const reg_value_base_t &r, const insn_t &insn);
631 inline void sll(const reg_value_base_t &r, const insn_t &insn);
634 inline void slr(const reg_value_base_t &r, const insn_t &insn);
637 inline void sar(const reg_value_base_t &r, const insn_t &insn);
641 inline void movt(const reg_value_base_t &r, const insn_t &insn);
643 inline void neg(const insn_t &insn);
645 inline void bnot(const insn_t &insn);
648 inline void add_num(uint64 r, const insn_t &insn);
649
653 inline void add_num(uint64 r);
656 inline void shift_left(uint64 r);
661 inline void shift_right(uint64 r, int nbytes = 0);
662
665 inline void extend(int width, bool is_signed);
666
668 qstring dstr(const procmod_t *pm = nullptr) const
669 {
670 qstring out;
671 reg_value_base_dstr(this, &out, pm);
672 return out;
673 }
674
675 // to use by reg_finder_t
676 // C++ does not allow making these methods protected and giving access to
677 // them only from this class, so I made these methods public.
678 // get the number (truncated to SLOTSIZE).
679 inline bool get_num(uint64 *uval, int slotsize) const;
680 // get the address (truncated to ADDRSIZE).
681 inline bool get_addr(ea_t *addr, int addrsize) const;
682 // get the SP delta (sign-extended to ADDRSIZE).
683 inline bool get_spd(sval_t *sval, int addrsize) const;
684 // if the value is a number, zero-truncate it to WIDTH.
685 // if it is an SP delta, sign-extend it to WIDTH.
686 // if WIDTH = 0, defaults to SLOTSIZE for numbers and ADDRSIZE for SP
687 // delta.
688 inline void truncate(int width, int slotsize, int addrsize);
689
690protected:
692
693 // helper implementation
694 set_compare_res_t vals_union_impl(const reg_value_base_t &r);
695 qstring dstr_impl(const procmod_t *pm) const;
696
697 // perform a binary operation
698 // This method does not change STATE,
699 // the caller should explicitly update it if necessary.
700 // \note Either THIS or R must have a single value.
701 inline bool perform_binary_op(
702 const reg_value_base_t &r,
703 arith_op_t aop,
704 const insn_t &insn);
705 // perform a binary operation if THIS and R are numbers
706 // if it cannot perform this operation it returns UNKINSN
707 inline void perform_binary_op_for_nums(
708 const reg_value_base_t &r,
709 arith_op_t aop,
710 const insn_t &insn);
711 // fix the sorting order and set VALS
712 template<class V>
713 inline void set_multivals(V *rvals, const insn_t &insn);
714 // fix the sorting order
715 inline void sort_multivals();
716
717 // check if value is alignment mask (small power of 2 minus 1)
718 bool is_mask() const
719 {
720 if ( !is_num() || !is_value_unique() )
721 return false;
722 uint64 mask = vals.begin()->val;
723 return is_pow2(mask + 1) && mask <= 0x1F;
724 }
725};
726
727//-------------------------------------------------------------------------
731struct reg_finder_t;
732struct reg_value_info_t : public reg_value_base_t
733{
734protected:
735 int slotsize = 0;
736 int addrsize = 0;
737
738public:
739 reg_value_info_t() : reg_value_base_t() {}
741 const reg_value_base_t &base,
742 int _slotsize,
743 int _addrsize)
744 : reg_value_base_t(base),
745 slotsize(_slotsize),
746 addrsize(_addrsize) {}
748 reg_value_base_t &&base,
749 int _slotsize,
750 int _addrsize)
751 : reg_value_base_t(base),
752 slotsize(_slotsize),
753 addrsize(_addrsize) {}
754
758 inline void set_context(int _slotsize, int _addrsize)
759 {
760 slotsize = _slotsize;
761 addrsize = _addrsize;
762 }
763 inline void set_context(const reg_finder_t *rf);
764
767 inline bool get_num(uint64 *uval) const
768 {
769 return reg_value_base_t::get_num(uval, slotsize);
770 }
771
774 inline bool get_addr(ea_t *addr) const
775 {
776 return reg_value_base_t::get_addr(addr, addrsize);
777 }
778
784 inline bool get_spd(sval_t *sval) const
785 {
786 return reg_value_base_t::get_spd(sval, addrsize);
787 }
788
794 inline void truncate(int width = 0)
795 {
796 reg_value_base_t::truncate(width, slotsize, addrsize);
797 }
798
800 inline void trunc_uval(const procmod_t &pm)
801 {
802 if ( !is_num() )
803 return;
804 if ( slotsize != 0 )
805 {
806 truncate();
807 return;
808 }
809 for ( auto &p : vals )
810 p.val = pm.trunc_uval(p.val);
811 sort_multivals();
812 }
813};
814
815//-------------------------------------------------------------------------
816// what operand are we going to track?
817struct reg_finder_op_t
818{
819private:
820 // |31 |30-29|28 |...
821 // |reg or stkvar|width|signness|...
822 // for registers:
823 // ...|27-16 |15-0 |
824 // ...|reserved|register number|
825 // for stkvars:
826 // ...|27 |26-0 |
827 // ...|stkoff sign|stkoff absolute value|
828 static constexpr uint32 REG = 0;
829 static constexpr uint32 STKVAR = 1 << 31;
830 static constexpr int WIDTH_SHIFT = 29;
831 static constexpr uint32 WIDTH_MASK = 0x3 << WIDTH_SHIFT;
832 static constexpr uint32 SIGNED = 1 << 28;
833 static constexpr int STKOFF_SIGNBIT = 1 << 27;
834 static constexpr uint32 STKOFF_MASK = STKOFF_SIGNBIT - 1;
835 // the impossible combination of bits
836 static constexpr uint32 BADREG = 0x10000;
837
838 uint32 packed = BADREG;
839
840 explicit reg_finder_op_t(uint32 _packed) : packed(_packed) {}
841
842public:
843 using rfop_t = reg_finder_op_t;
845 reg_finder_op_t(const rfop_t &r) = default;
846 rfop_t &operator=(const rfop_t &r) = default;
847
848 // if after constructors empty() returns 'true'
849 // that means that arguments are bad
850 bool empty() const { return packed == BADREG; }
851 void clear() { packed = BADREG; }
852
853 static bool is_valid_reg(int reg)
854 {
855 return reg >= 0 && reg < BADREG;
856 }
857 inline static reg_finder_op_t make_reg(int reg, int width);
858
859 static bool is_valid_stkoff(sval_t stkoff)
860 {
861 return stkoff >= -sval_t(STKOFF_MASK) && stkoff <= sval_t(STKOFF_MASK);
862 }
863 inline static reg_finder_op_t make_stkoff(sval_t stkoff, int width);
864 inline static int get_op_width(const op_t &op);
865
866 inline void set_width(int width);
867 inline void set_signness(bool is_signed);
868 inline void set_width_signness(int width, bool is_signed);
869
870 bool is_reg() const { return (packed & STKVAR) == 0; }
871 bool is_stkvar() const { return (packed & STKVAR) != 0; }
872 bool is_signed() const { return (packed & SIGNED) != 0; }
873 int get_width() const
874 {
875 return 1 << ((packed & WIDTH_MASK) >> WIDTH_SHIFT);
876 }
877
878 uint16 get_reg() const { return uint16(packed); }
880 {
881 sval_t stkoff = packed & STKOFF_MASK;
882 return (packed & STKOFF_SIGNBIT) == 0 ? stkoff : -stkoff;
883 }
884
885 bool is_reg(int reg) const { return is_reg() && get_reg() == reg; }
886
887 DECLARE_COMPARISONS(reg_finder_op_t)
888 {
889 // the empty object is less than any other object
890 if ( empty() )
891 return r.empty() ? 0 : -1;
892 if ( r.empty() )
893 return 1;
894 return ::compare(packed, r.packed);
895 }
896
897protected:
898 inline static uint32 pack_width(int width);
899};
900
901//-------------------------------------------------------------------------
902struct reg_value_ud_chain_t;
904 reg_value_base_t *v1,
905 reg_value_base_t *v2,
906 const insn_t &insn,
907 void *ud);
908
909#define DECLARE_REG_FINDER_HELPERS(decl)\
910decl void ida_export reg_finder_invalidate_cache(reg_finder_t *_this, ea_t to, ea_t from, cref_t cref);\
911decl void ida_export reg_finder_invalidate_xrefs_cache(reg_finder_t *_this, ea_t ea, dref_t dref);\
912decl void ida_export reg_finder_find(reg_finder_t *_this, reg_value_base_t *out, ea_t ea, ea_t ds, reg_finder_op_t op, int max_depth, size_t linear_insns);\
913decl void ida_export reg_finder94_make_rfop(reg_finder_t *_this, reg_finder_op_t *rfop, const op_t *op, const insn_t *insn, ea_t func_ea);\
914decl bool ida_export reg_finder_calc_op_addr(reg_finder_t *_this, reg_value_base_t *addr, const op_t *memop, const insn_t *insn, ea_t ea, ea_t ds, int max_depth);\
915decl bool ida_export reg_finder_emulate_mem_read(reg_finder_t *_this, reg_value_base_t *value, const reg_value_base_t *addr, int width, bool is_signed, const insn_t *insn);\
916decl void ida_export reg_finder_emulate_binary_op(reg_finder_t *_this, reg_value_base_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);\
917decl void ida_export reg_finder_emulate_unary_op(reg_finder_t *_this, reg_value_base_t *value, int aop, int reg, const insn_t *insn, ea_t ea, ea_t ds);\
918decl void ida_export reg_finder_emulate_binary_op_shifted(reg_finder_t *_this, reg_value_base_t *value, int aop, const op_t *op1, const op_t *op2, int width, bool is_signed, int shift, uint8 shift_count, const insn_t *insn, ea_t ea, ea_t ds);\
919decl bool ida_export reg_finder_may_modify_stkvar(reg_finder_t *_this, reg_value_base_t *value, reg_finder_op_t op, const insn_t *insn);\
920decl bool ida_export reg_finder_can_resolve_mem(const reg_finder_t *_this, ea_t ea);\
921decl void ida_export reg_finder_ctr(reg_finder_t *_this);\
922decl void ida_export reg_finder_dtr(reg_finder_t *_this);
923
925
926//-------------------------------------------------------------------------
927//lint -e{958} padding needed
928struct reg_finder_block_t;
929struct reg_finder_pred_t;
931{
932 const procmod_t &pm;
933 const int proc_maxop; // max number of operands in insns
934 uint32 flags; // a set of RF_... bits
935 // new public fields after 9.3
936 int addrsize; // the address size in bytes (4 or 8)
937 int slotsize; // the register size in bytes (4 or 8)
938 // new public fields after 9.4 (keep offsets above for ABI compat)
939
940 // ADDRSIZE should match to the application bitness. This structure stores
941 // a local copy of this value, initialized via get_effective_addrsize().
942 // \sa update_sizes()
943 // ATM the regfinder cannot handle 16-bit addresses. However, certain
944 // older ARM databases have incorrect bitness set to 16 when the actual
945 // application is 32-bit. This wrapper returns the correct size (4 or 8).
947 {
948 return inf_get_effective_addrsize() < 8 ? 4 : 8;
949 }
950
951 // a call insn may modify stkvars (via aliased stkvars passed as args).
952 // this bit indicates how to answer this question.
953 static constexpr uint32 RF_DOES_CALL_SPOIL_STKVARS = 0x0001;
954 // this bit allows to use the write-xrefs cache. if it is set then the
955 // proc module has to call invalidate_xrefs_cache() on the events:
956 // - ev_add_dref
957 // - ev_del_dref
958 static constexpr uint32 RF_ALLOW_XREFS_CACHE = 0x0002;
959
961 {
962 return (flags & RF_DOES_CALL_SPOIL_STKVARS) != 0;
963 }
964 bool allow_xrefs_cache() const
965 {
966 return (flags & RF_ALLOW_XREFS_CACHE) != 0;
967 }
968
969protected:
971 using rvb_t = reg_value_base_t;
975 friend struct reg_finder_block_t;
976 friend struct reg_finder_pred_t;
977
978 // the data members below are set by the each call of find()
979 ea_t cur_func_ea = BADADDR; // function to search in
981 bool fixed_max_depth = false; // is the initial MAX_DEPTH specified by the
982 // caller (not taken from ida.cfg) ?
983 int cur_max_depth = 0; // maximum search depth
984 int cur_call_depth = 0; // the current depth of recursive calls
985 size_t linear_flow_cnt = 0; // the number of insn to search in the
986 // linear flow (if != 0)
987 bool only_linear_flow() const { return linear_flow_cnt != 0; }
988 // ABORTING_EA is kept at its 9.3 offset (72): a 9.3-built make_rfop() writes
989 // aborting_ea=BADADDR, and if it were elsewhere it would clobber another
990 // field. Keep it before BBLK_CNT for that reason.
991 ea_t aborting_ea = BADADDR; // to make tracking aborting easier
992 size_t bblk_cnt = 0; // the number of insn in a basic block
993 rvb_t standalone_value; // to return a value for the initial block
994 // without addresses
995
996 static constexpr size_t NO_CHAIN = size_t(-1);
997
998 // a temporary storage to return from is_move_insn()
1001
1002 // the condition under which the instruction is executed,
1003 // and some additional instruction features
1004 struct cond_t
1005 {
1006 private:
1007 uint32 packed;
1008 static constexpr uint32 COND_MASK = 0x0F;
1009 static constexpr int KIND_SHIFT = 4;
1010 static constexpr uint32 KIND_MASK = 0xF;
1011
1012 public:
1013 // got from arm.hpp
1014 enum : uchar
1015 {
1016 EQ, // 0000 Z Equal
1017 NE, // 0001 !Z Not equal
1018 CS, // 0010 C Unsigned higher or same
1019 CC, // 0011 !C Unsigned lower
1020 MI, // 0100 N Negative
1021 PL, // 0101 !N Positive or Zero
1022 VS, // 0110 V Overflow
1023 VC, // 0111 !V No overflow
1024 HI, // 1000 C & !Z Unsigned higher
1025 LS, // 1001 !C | Z Unsigned lower or same
1026 GE, // 1010 (N & V) | (!N & !V) Greater or equal
1027 LT, // 1011 (N & !V) | (!N & V) Less than
1028 GT, // 1100 !Z & ((N & V)|(!N & !V)) Greater than
1029 LE, // 1101 Z | (N & !V) | (!N & V) Less than or equal
1030 AL, // 1110 Always
1031 NV, // 1111 Never
1032 };
1033
1034 enum : uchar
1035 {
1039 };
1040
1041 cond_t(uchar cond = AL, uchar kind = NONE)
1042 : packed((cond & COND_MASK) | ((kind & KIND_MASK) << KIND_SHIFT)) {}
1043
1044 uchar get_cond() const { return uchar(packed & COND_MASK); }
1045 // e.g. GE includes GE, GT, EQ
1046 // MOVGE ... this insn is executed if the branch is taken
1047 // BGT away
1049 {
1050 // TODO implement non-trivial cases
1051 uchar cnd = get_cond();
1052 uchar rcnd = r.get_cond();
1053 // AL includes all other conditions
1054 return cnd == rcnd || rcnd == AL;
1055 }
1056
1058 {
1059 return uchar((packed >> KIND_SHIFT) & KIND_MASK);
1060 }
1061 bool modifies_cond_codes() const { return get_kind() == MODIFIES_CC; }
1062 bool jumps() const { return get_kind() == JUMPS; }
1063 };
1064
1065private:
1066 using udc_t = reg_value_ud_chain_t;
1067
1069 struct reg_finder_chainvec_t *chains = nullptr; // the chain values
1070
1071 struct addr_t
1072 {
1073 ea_t ea;
1074 rfop_t rfop;
1075 addr_t(ea_t _ea, rfop_t _rfop = rfop_t()) : ea(_ea), rfop(_rfop) {}
1076 DECLARE_COMPARISONS(addr_t)
1077 {
1078 int code = ::compare(ea, r.ea);
1079 if ( code == 0 )
1080 code = rfop.compare(r.rfop);
1081 return code;
1082 }
1083 };
1084 // where does the value come from?
1085 struct vref_t
1086 {
1087 size_t chain_num; // the chain number
1088 sval_t delta; // the addend to the chain value
1089 explicit vref_t(
1090 size_t _chain_num = reg_finder_t::NO_CHAIN,
1091 sval_t _delta = 0)
1092 : chain_num(_chain_num), delta(_delta) {}
1093 bool empty() const { return chain_num == reg_finder_t::NO_CHAIN; }
1094 void clear() { chain_num = reg_finder_t::NO_CHAIN; delta = 0; }
1095 bool operator==(const vref_t &r)
1096 {
1097 return chain_num == r.chain_num && delta == r.delta;
1098 }
1099 };
1100
1101 // key - an operand and an address,
1102 // value - the reference to the value of the register at this address
1103 // (the chain value + DELTA)
1104 friend struct reg_finder_rfop_chains_t; // the opaque type
1105 struct reg_finder_rfop_chains_t *rfop_chains = nullptr;
1106
1107 // the path of depth-first search
1108 qvector<vref_t> path;
1109
1110 // the cache of the write xrefs of addresses in read-only segments.
1111 // this cache is used only if the regfinder is created with the
1112 // RF_ALLOW_XREFS_CACHE bit.
1113 friend struct reg_finder_xrefs_cache_t; // the opaque type
1114 struct reg_finder_xrefs_cache_t *xrefs_cache = nullptr;
1115
1116 bool in_invalidate = false; // the guard for invalidate_regfinder_cache()
1117 bool debug_on = true;
1118
1119protected:
1120 // The constructor is protected on purpose: reg_finder_t is meant to be
1121 // used only as a base for internal processor-specific finders. External
1122 // code must go through the convenience functions (find_reg_value_info(),
1123 // find_sp_value(), ...).
1125 const procmod_t &_pm,
1126 int _proc_maxop = 3,
1128 : pm(_pm),
1129 proc_maxop(_proc_maxop),
1130 flags(_flags),
1133 {
1134 reg_finder_ctr(this);
1135 }
1136
1137public:
1138 virtual ~reg_finder_t() { reg_finder_dtr(this); }
1139
1140 // this method must be called when the register size does not match the
1141 // application bitness, or when the application bitness changes.
1142 bool update_sizes(int _slotsize = 0)
1143 {
1144 int _addrsize = get_effective_addrsize();
1145 if ( _slotsize == 0 )
1146 _slotsize = _addrsize;
1147 else if ( _slotsize != 4 && _slotsize != 8 || _slotsize < _addrsize )
1148 return false;
1149 addrsize = _addrsize;
1150 slotsize = _slotsize;
1151 return true;
1152 }
1153
1154 // the code xref from FROM to TO was added or deleted.
1155 // if we have TO address in the cache we should invalidate the value at
1156 // this address and the dependent values.
1157 void invalidate_cache(ea_t to, ea_t from, cref_t cref)
1158 {
1159 reg_finder_invalidate_cache(this, to, from, cref);
1160 }
1161 // clear the entire cache.
1163 {
1164 reg_finder_invalidate_cache(this, BADADDR, BADADDR, fl_U);
1165 }
1166
1167 // a new data xref to EA was added or deleted.
1168 // \sa RF_ALLOW_XREFS_CACHE
1170 {
1171 reg_finder_invalidate_xrefs_cache(this, ea, dref);
1172 }
1173
1174 // find a value of OP before EA
1175 // \param max_depth the maximum search depth.
1176 // 0 means the value of REGTRACK_MAX_DEPTH or
1177 // REGTRACK_FUNC_MAX_DEPTH from ida.cfg depending on the
1178 // register,
1179 // -1 means always the value of REGTRACK_FUNC_MAX_DEPTH.
1180 // A value greater than 1 cannot be used in recursive
1181 // calls of find() (e.g. from emulate_insn()).
1182 // \param linear_insns a non-zero value causes switching to the linear
1183 // flow search mode. In this mode the search stops at
1184 // the first xref or when LINEAR_INSNS insns are
1185 // tracked. The number of instructions tracked is
1186 // counted from the address of the first call with a
1187 // non-zero argument, i.e. recursive calls to find()
1188 // after switching to this mode ignore this argument.
1190 ea_t ea,
1191 rfop_t rfop,
1192 int max_depth = 0,
1193 size_t linear_insns = 0)
1194 {
1195 rvb_t ret;
1196 flow_t flow = process_delay_slot(pm.trunc_uval(ea), fl_U);
1197 reg_finder_find(this, &ret,
1198 flow.ea, flow.ds, rfop,
1199 max_depth, linear_insns);
1200 return rvi_t(std::move(ret), rfop.get_width(), addrsize);
1201 }
1202
1203 // find the value of any of the two registers
1205 reg_value_info_t *rvi,
1206 ea_t ea,
1207 const int reg[2],
1208 size_t linear_insns = 10)
1209 {
1210 if ( reg[0] == reg[1] )
1211 return -1;
1212 *rvi = find(ea, rfop_t::make_reg(reg[0], slotsize), 0, linear_insns);
1213 if ( rvi->is_known() )
1214 return 0;
1215 *rvi = find(ea, rfop_t::make_reg(reg[1], slotsize), 0, linear_insns);
1216 if ( rvi->is_known() )
1217 return 1;
1218 *rvi = find(ea, rfop_t::make_reg(reg[0], slotsize), 0);
1219 if ( rvi->is_known() )
1220 return 0;
1221 *rvi = find(ea, rfop_t::make_reg(reg[1], slotsize), 0);
1222 if ( rvi->is_known() )
1223 return 1;
1224 return -1;
1225 }
1226
1227 // find a value of non-SP based register before EA
1228 // (truncated to SLOTSIZE)
1229 bool find_const(uint64 *val, ea_t ea, rfop_t rfop, int max_depth = 0)
1230 {
1231 return find(ea, rfop, max_depth).get_num(val);
1232 }
1233
1234 // find an address of non-SP based register before EA
1235 // (truncated to ADDRSIZE)
1236 bool find_addr(ea_t *addr, ea_t ea, rfop_t rfop, int max_depth = 0)
1237 {
1238 return find(ea, rfop, max_depth).get_addr(addr);
1239 }
1240
1241 // find a value of SP based register before EA
1242 // by default it uses the SP register and REGTRACK_FUNC_MAX_DEPTH
1243 bool find_spd(sval_t *spval, ea_t ea, int reg = -1, int max_depth = -1)
1244 {
1245 if ( reg == -1 )
1246 {
1247 reg = get_sp_reg(ea);
1248 if ( reg == -1 )
1249 return false;
1250 }
1251 rfop_t rfop = rfop_t::make_reg(reg, addrsize);
1252 return find(ea, rfop, max_depth).get_spd(spval);
1253 }
1254
1255 // make the regfinder operand from the insn operand.
1256 // if OP is unsupported this function returns an empty operand.
1257 rfop_t make_rfop(const op_t &_op, const insn_t &insn, ea_t func_ea)
1258 {
1259 op_t op = _op; // make a copy
1260 if ( !can_track_op(&op, insn, func_ea) )
1261 return rfop_t();
1262 rfop_t res;
1263 reg_finder94_make_rfop(this, &res, &op, &insn, func_ea);
1264 aborting_ea = BADADDR; // ignore for this call
1265 return res;
1266 }
1267
1268 // find the operand addresses (o_displ or o_phrase or o_mem)
1269 // \li in the case of 'o_displ', the address is formed by adding
1270 // memop.addr to the content of memop.phrase
1271 // \li in the case of 'o_phrase', the address is formed by adding
1272 // memop.addr to the sum of the content of memop.phrase and the content of
1273 // the second register (memop.value), \sa procmod_t::make_op_phrase()
1274 // \li in the case of 'o_mem', the address is just memop.addr
1275 // \param memop the operand
1276 // \param insn the emulated insn
1277 // \param max_depth the maximum search depth.
1279 const op_t &memop,
1280 const insn_t &insn,
1281 int max_depth = 0)
1282 {
1283 rvb_t ret;
1284 flow_t flow = process_delay_slot(insn.ea, fl_U);
1285 reg_finder_calc_op_addr(this, &ret,
1286 &memop,
1287 &insn, flow.ea, flow.ds, max_depth);
1288 return rvi_t(std::move(ret), slotsize, addrsize);
1289 }
1290
1291 // handle a memory read
1292 // \note this method checks that the address belongs to the readonly
1293 // segment, if not it calls is_mem_readonly() to make an additional
1294 // check.
1295 // \param addr the address to read from.
1296 // this parameter may be the same as VALUE.
1297 // \param width the data width. it must be 1/2/4/8.
1298 // \sa get_data_value()
1299 // \param is_signed if 'true' the result should be sign-extended
1300 // \param insn the emulated insn
1302 rvb_t *value,
1303 const rvb_t &addr,
1304 int width,
1305 bool is_signed,
1306 const insn_t &insn)
1307 {
1308 reg_finder_emulate_mem_read(this, value, &addr,
1309 width, is_signed,
1310 &insn);
1311 }
1312
1313 // is memory at EA read-only?
1314 bool can_resolve_mem(ea_t ea) const
1315 {
1316 return reg_finder_can_resolve_mem(this, ea);
1317 }
1318
1319 friend struct reg_finder_debug_t;
1320
1321protected:
1322 // the address of the emulated instruction, taking into account a possible
1323 // delay slot
1324 struct flow_t
1325 {
1327 ea_t ds; // to handle a delay slot
1328 bool has_delay_slot() const { return ds != BADADDR; }
1329 // pre-condidition: has_delay_slot()
1330 bool is_ea_handled() const { return ds > ea; }
1331 // pre-condidition: is_ea_handled()
1333
1334 flow_t(ea_t _ea, ea_t _ds = BADADDR) : ea(_ea), ds(_ds) {}
1335
1336 // the address of the actually emulated insn
1337 // when handling a delay slot we are actually emulating the main insn
1338 // 00 func:
1339 // 00 beq ..., @away # $t9 is not 00 because it is modified in the
1340 // # delay slot
1341 // 04 addui $t9, ... # $t9 is 00 before this insn
1342 ea_t actual_ea() const { return has_delay_slot() ? ds : ea; }
1343 operator ea_t() const { return actual_ea(); }
1344
1345 bool operator<(const flow_t &r) const { return ea < r.ea; }
1346 };
1347
1348 // processor specific methods
1349
1350 // we reached EA using REF.
1351 // For processors with delay slots we can process another insn first.
1352 // 00 jal main
1353 // 04 addiu $a1, $v0, 4 <-- EA but we should start with 00
1354 // \param ref how did we reach EA?
1355 // - fl_F: by the ordinary flow,
1356 // - fl_JN, fl_JF: by the jump,
1357 // - fl_U: from the find() method.
1358 virtual flow_t process_delay_slot(ea_t ea, cref_t /*ref*/) const
1359 {
1360 return flow_t(ea); // no delay slots
1361 }
1362
1363 // an instruction may be executed under a condition
1364 virtual cond_t get_cond(ea_t ea) const
1365 {
1366 qnotused(ea);
1367 return cond_t(); // no conditional instructions
1368 }
1369
1370 // we may know the value of some registers
1371 // \retval empty() we know nothing
1372 // \retval is_unkfunc() there may be any value (e.g. a func argument)
1373 // \retval is_known() we found the value (e.g. the GOT register)
1375 flow_t flow,
1376 rfop_t rfop,
1377 bool is_func_start) const
1378 {
1379 qnotused(rfop);
1380 qnotused(flow);
1381 qnotused(is_func_start);
1382 return rvb_t(); // know nothing about registers
1383 }
1384
1385 // is the content of memory at EA a constant?
1386 // \note this method is called from emulate_mem_read() if it cannot itself
1387 // determine that this memory is read-only.
1388 virtual bool is_mem_readonly(ea_t /*ea*/) const
1389 {
1390 return false;
1391 }
1392
1393 // get the SP register
1394 virtual int get_sp_reg(ea_t ea) const
1395 {
1396 qnotused(ea);
1397 return -1;
1398 }
1399
1400 // is REG used throughout the function?
1401 virtual bool is_funcwide_reg(ea_t ea, int reg) const
1402 {
1403 return reg == get_sp_reg(ea);
1404 }
1405
1406 // 9.3-ABI slot
1407 // Kept inline so the vtable stays weak (no key function).
1408 virtual bool can_track_op93(op_t *op, const insn_t &insn, range_t *pfn) const //lint !e818
1409 {
1410 return can_track_op(op, insn, pfn != nullptr ? pfn->start_ea : BADADDR);
1411 }
1412
1413 // is INSN a 'move' instruction? (or a simple add/sub instruction)
1415 {
1416 // the first case (if !new_rfop.empty()):
1417 // is_move_insn() already knows the new tracked operand
1419
1420 // the second case (if new_rfop.empty()):
1421 // the operand types should be byte/word/dword/qword
1422 // both DST_OP and SRC_OP cannot be memory operands
1423 // the pointer to the source operand
1424 const op_t *dst_op = nullptr;
1425 // the pointer to the destination operand
1426 const op_t *src_op = nullptr;
1427 // if 'true' and DST_OP is wider than SRC_OP then the source operand
1428 // will be sign extended
1429 bool is_signed = false;
1430
1431 // if non-zero then the instruction is a simple 'add/sub' insn with an
1432 // immediate value. the operands must have the same size.
1433 // \note this member is used by both cases.
1434 // DELTA is positive for the 'add' insn.
1436 };
1437 // \param [out] move_desc the decription of the 'move' insn
1438 // \param [in] rfop the operand to find a value of
1439 // \param insn the emulating insn
1440 // \retval false if INSN is not a 'move' insn
1441 // \retval true INSN is a 'move' insn
1442 virtual bool is_move_insn(
1443 move_desc_t *move_desc,
1444 const rfop_t &rfop,
1445 const insn_t &insn)
1446 {
1447 qnotused(move_desc);
1448 qnotused(rfop);
1449 qnotused(insn);
1450 return false;
1451 }
1452
1453 // emulate INSN and find the value of OP
1454 // to get values of the source registers this method may call find()
1455 // (this call will be recursive)
1456 // \param [out] value only if the method returns 'true'
1457 // is_dead_end(): there is no flow to this insn
1458 // aborted(): the tracking process was aborted
1459 // is_unkinsn(): INSN spoils OP in an unknown way
1460 // is_known(): the found value
1461 // \param [in] rfop the operand to find a value of
1462 // \param [in] insn the instruction to emulate
1463 // \param [in] flow the control flow to get a preceding insn.
1464 // it will be passed to find().
1465 // \retval true the found value is in VALUE
1466 // \retval false INSN does not modify OP
1467 virtual bool emulate_insn(
1468 rvb_t *value,
1469 const rfop_t &rfop,
1470 const insn_t &insn,
1471 flow_t flow)
1472 {
1473 qnotused(rfop);
1474 qnotused(flow);
1475 value->set_unkinsn(insn); // do not support any instruction
1476 return true;
1477 }
1478
1479 // we can track only registers and stkvars (including BP-based)
1480 // NB: added at the END of the vtable so can_track_op's original slot keeps
1481 // the 9.3 signature via can_track_op93().
1482 virtual bool can_track_op(op_t *op, const insn_t &insn, ea_t func_ea) const
1483 {
1484 qnotused(op);
1485 qnotused(insn);
1486 qnotused(func_ea);
1487 return false;
1488 }
1489
1490 // helper methods for emulate_insn()
1491
1492 // get values of the operand from emulate_insn()
1493 // \param flow the control flow to get a starting insn
1494 // \param rfop the operand to find a value of
1496 {
1497 rvb_t ret;
1498 reg_finder_find(this, &ret, flow.ea, flow.ds, rfop, 0, 0);
1499 return ret;
1500 }
1501
1502 // get values of the register from emulate_insn()
1503 // \param flow the control flow to get a starting insn
1504 // \param reg the register to find a value of
1505 rvb_t find(flow_t flow, int reg)
1506 {
1507 rvb_t ret;
1508 rfop_t rfop = rfop_t::make_reg(reg, slotsize);
1509 reg_finder_find(this, &ret, flow.ea, flow.ds, rfop, 0, 0);
1510 return ret;
1511 }
1512
1513 // get operand addresses (o_displ or o_phrase or o_mem)
1514 // \sa find_op_addr()
1516 rvb_t *addr,
1517 const op_t &memop,
1518 const insn_t &insn,
1519 flow_t flow)
1520 {
1521 reg_finder_calc_op_addr(this, addr,
1522 &memop,
1523 &insn, flow.ea, flow.ds, 0);
1524 }
1525
1526 // get OP1 AOP OP2
1527 // \note The operation is performed considering the value size is
1528 // SLOTSIZE, i.e. for SAR, this means the value is sign-extended before
1529 // the shift is applied.
1531 rvb_t *value,
1532 rvb_t::arith_op_t aop, // not NEG, NOT
1533 const op_t &op1,
1534 const op_t &op2,
1535 const insn_t &insn,
1536 flow_t flow,
1537 reg_finder_binary_ops_adjust_fun adjust = nullptr,
1538 void *ud = nullptr)
1539 {
1540 reg_finder_emulate_binary_op(this, value,
1541 aop, &op1, &op2,
1542 &insn, flow.ea, flow.ds,
1543 adjust, ud);
1544 }
1545
1546 // get AOP REG
1548 rvb_t *value,
1549 rvb_t::arith_op_t aop, // only NEG, NOT
1550 int reg,
1551 const insn_t &insn,
1552 flow_t flow)
1553 {
1554 reg_finder_emulate_unary_op(this, value,
1555 aop, reg,
1556 &insn, flow.ea, flow.ds);
1557 }
1558
1559 // get OP1 AOP shift(extend(OP2, WIDTH, iS_SIGNED), SHIFT, SHIFT_COUNT)
1561 rvb_t *value,
1562 rvb_t::arith_op_t aop, // only ADD, SUB, OR, AND, XOR, AND_NOT
1563 const op_t &op1,
1564 const op_t &op2,
1565 int width, // 0 means no extension
1566 bool is_signed,
1567 rvb_t::arith_op_t shift, // only SLL, SLR, SAR
1568 uint8 shift_count,
1569 const insn_t &insn,
1570 flow_t flow)
1571 {
1572 reg_finder_emulate_binary_op_shifted(this, value,
1573 aop, &op1, &op2,
1574 width, is_signed,
1575 shift, shift_count,
1576 &insn, flow.ea, flow.ds);
1577 }
1578
1579 // this method returns 'true' and sets VALUE to UNKINSN if there is the
1580 // slightest possibility that INSN changes OP (it is a stkvar).
1581 // in the current implementation we assume that any store instruction with
1582 // an unknown address or any call instruction may modify stkvars.
1583 bool may_modify_stkvar(rvb_t *value, rfop_t rfop, const insn_t &insn)
1584 {
1585 return reg_finder_may_modify_stkvar(this, value, rfop, &insn);
1586 }
1587
1588private:
1589 // implementation methods
1590 rvb_t find_chain(const flow_t flow, const rfop_t rfop);
1591 void create_initial_block(const flow_t flow, const rfop_t rfop);
1592 // these 2 methods may set ABORTING_EA to abort tracking
1593 bool create_new_block(vref_t *res_vref, const pred_t &pred);
1594 bool handle_block_pred(size_t chain_num, vref_t pred_vref);
1595 vref_t finalize_block();
1596
1597 // for create_new_block()
1598 bool collect_predecessors(qvector<flow_t> *pred_addrs, flow_t flow) const;
1599 bool analyze_linear_flow(
1600 qvector<flow_t> *pred_addrs,
1601 eavec_t *to_eas,
1602 ea_t initial_ea) const;
1603 bool merge_loop_blocks(const block_t *loop_block, sval_t delta);
1604 bool decode_and_emulate_insn(
1605 rvb_t *value,
1606 rfop_t *rfop,
1607 sval_t *delta,
1608 flow_t flow);
1609 bool is_same_func(ea_t ea) const
1610 {
1611 return cur_func_ea != BADADDR
1613 : !get_fchunk_info(nullptr, ea);
1614 }
1615 rvb_t make_aborted();
1616 bool set_aborted_or_unkinsn(rvb_t *value, const insn_t &insn);
1617
1618 // what to do after move handling?
1619 enum handle_move_res_t
1620 {
1621 HANDLED, // the move is handled, we get a new tracked operand or
1622 // we are sure that it is not spoiled
1623 UNSUPPORTED, // the move does not touch the tracked operand
1624 SPOILED, // a partial modification of the tracked operand is
1625 // detected
1626 };
1627 // handle a move to a tracked register
1628 // \note the operand types should be byte/word/dword/qword.
1629 // \note it may set ABORTING_EA if it returned SPOILED.
1630 // \param [inout] rfop the tracked operand
1631 // \param move_desc the decription of the 'move' insn
1632 // (move_desc_t::delta is not used in this function)
1633 // \param insn the move instruction
1634 handle_move_res_t handle_move(
1635 rfop_t *rfop,
1636 const move_desc_t &move_desc,
1637 const insn_t &insn);
1638
1639 // for SAME the operand widths may be different.
1640 // if it failed to calculate the stkvar offset it returns OVERLAPS.
1641 // \note it may set ABORTING_EA if it returned OVERLAPS.
1642 enum overlap_res_t { SAME, OVERLAPS, DIFFERENT };
1643 overlap_res_t does_rfop_overlap_with_op(
1644 rfop_t rfop,
1645 const op_t &op,
1646 const insn_t &insn);
1647
1648 // it returns success
1649 // \note it may set ABORTING_EA if it returned 'false'.
1650 bool calc_stkvar_off(
1651 sval_t *stkoff,
1652 const op_t &op,
1653 const insn_t &insn,
1654 ea_t func_ea);
1655
1656 // to work with chains
1657 reg_value_ud_chain_t &get_chain(size_t chain_num);
1658 const reg_value_ud_chain_t &get_chain(size_t chain_num) const;
1659 void erase_block(size_t chain_num);
1660 // move addresses to the block of TO_CHAIN_NUM adjusting deltas
1661 void move_addrs(
1662 size_t from_chain_num,
1663 size_t to_chain_num,
1664 sval_t delta);
1665 void adjust_deltas(const qvector<addr_t> &addrs, sval_t delta);
1666 void trim_cache(ea_t ea, int max_cache_size);
1667 // does RFOP has at FLOW a value different from CHAIN_NUM?
1668 bool is_rfop_changed(
1669 const flow_t flow,
1670 const rfop_t rfop,
1671 size_t chain_num);
1672
1673 DECLARE_REG_FINDER_HELPERS(friend)
1674
1675 // helper implementation
1676 void invalidate_cache_impl(ea_t to, ea_t from, cref_t cref);
1677 void invalidate_xrefs_cache_impl(ea_t ea, dref_t dref);
1678 rvb_t find_impl(flow_t flow, rfop_t rfop, int max_depth, size_t linear_insns);
1679 rvb_t find_impl2(flow_t flow, rfop_t rfop, int max_depth, size_t linear_insns);
1680 rvb_t find_impl(flow_t flow, const op_t &op);
1681 rvb_t find_impl(flow_t flow, int reg, int max_depth = 0)
1682 {
1683 return find_impl(flow, rfop_t::make_reg(reg, slotsize), max_depth, 0);
1684 }
1685 rfop_t make_rfop_impl(const op_t &op, const insn_t &insn, ea_t func_ea);
1686 bool calc_op_addr_impl(
1687 rvb_t *addr,
1688 const op_t &memop,
1689 const insn_t &insn,
1690 flow_t flow,
1691 int max_depth);
1692 bool emulate_mem_read_impl(
1693 rvb_t *value,
1694 const rvb_t &addr,
1695 int width,
1696 bool is_signed,
1697 const insn_t &insn);
1698 void emulate_binary_op_impl(
1699 rvb_t *value,
1700 rvb_t::arith_op_t aop, // not NEG, NOT
1701 const op_t &op1,
1702 const op_t &op2,
1703 const insn_t &insn,
1704 flow_t flow,
1705 reg_finder_binary_ops_adjust_fun adjust = nullptr,
1706 void *ud = nullptr);
1707 void emulate_unary_op_impl(
1708 rvb_t *value,
1709 rvb_t::arith_op_t aop, // only NEG, NOT
1710 int reg,
1711 const insn_t &insn,
1712 flow_t flow);
1713 void emulate_binary_op_shifted_impl(
1714 rvb_t *value,
1715 rvb_t::arith_op_t aop, // only ADD, SUB, OR, AND, XOR, AND_NOT
1716 const op_t &op1,
1717 const op_t &op2,
1718 int width, // 0 means no extension
1719 bool is_signed,
1720 rvb_t::arith_op_t shift, // only SLL, SLR, SAR
1721 uint8 shift_count,
1722 const insn_t &insn,
1723 flow_t flow);
1724 bool may_modify_stkvar_impl(
1725 rvb_t *value,
1726 rfop_t rfop,
1727 const insn_t &insn);
1728 bool can_resolve_mem_impl(ea_t ea) const;
1729};
1730
1731//-------------------------------------------------------------------------
1732// compatibility helpers
1733//-------------------------------------------------------------------------
1734idaman bool ida_export reg_finder94_find_reg_value_info(reg_value_info_t *out, ea_t ea, int reg, int max_depth);
1735idaman int ida_export reg_finder94_find_nearest_rvi(reg_value_info_t *rvi, ea_t ea, const int reg[2]);
1736
1737//-------------------------------------------------------------------------
1738// convenience functions
1739//-------------------------------------------------------------------------
1750idaman int ida_export find_reg_value(uint64 *uval, ea_t ea, int reg);
1751
1752//-------------------------------------------------------------------------
1764idaman int ida_export find_sp_value(sval_t *sval, ea_t ea, int reg = -1);
1765
1766//-------------------------------------------------------------------------
1788#ifndef IDA_REGFINDER_LEGACY_COMPAT
1789inline bool ida_export find_reg_value_info(
1790 reg_value_info_t *rvi,
1791 ea_t ea,
1792 int reg,
1793 int max_depth = 0)
1794{
1795 return reg_finder94_find_reg_value_info(rvi, ea, reg, max_depth);
1796}
1797#endif
1798
1799//-------------------------------------------------------------------------
1817idaman bool ida_export find_regname_value_info(
1818 reg_value_info_t *rvi,
1819 ea_t ea,
1820 const char *regname,
1821 int max_depth = 0);
1822
1823//-------------------------------------------------------------------------
1832#ifndef IDA_REGFINDER_LEGACY_COMPAT
1833inline int ida_export find_nearest_rvi(
1834 reg_value_info_t *rvi,
1835 ea_t ea,
1836 const int reg[2])
1837{
1838 return reg_finder94_find_nearest_rvi(rvi, ea, reg);
1839}
1840#endif
1841
1842//-------------------------------------------------------------------------
1847idaman void ida_export invalidate_regfinder_cache(
1848 ea_t to = BADADDR,
1849 ea_t from = BADADDR,
1850 cref_t cref = fl_U);
1851
1852//-------------------------------------------------------------------------
1857 ea_t to = BADADDR,
1858 dref_t dref = dr_O);
1859
1860//-------------------------------------------------------------------------
1861// inline methods
1862//-------------------------------------------------------------------------
1863inline bool reg_value_base_t::perform_binary_op(
1864 const reg_value_base_t &r,
1865 arith_op_t aop,
1866 const insn_t &insn)
1867{
1868 const reg_value_base_t *mv;
1869 uint64 sv;
1870 if ( r.is_value_unique() )
1871 {
1872 mv = this;
1873 sv = r.vals.begin()->val;
1874 }
1875 else if ( is_value_unique() )
1876 {
1877 mv = &r;
1878 sv = vals.begin()->val;
1879 }
1880 else
1881 {
1882 return false; // both THIS and R have multiple values
1883 }
1884 qvector<uint64> rvals;
1885 rvals.reserve(mv->vals.size());
1886 for ( const auto &p : mv->vals )
1887 {
1888 uint64 res;
1889 switch ( aop )
1890 {
1891 case ADD: res = p.val + sv; break;
1892 case SUB: res = p.val - sv; break;
1893 case OR: res = p.val | sv; break;
1894 case AND: res = p.val & sv; break;
1895 case XOR: res = p.val ^ sv; break;
1896 case AND_NOT: res = p.val & ~sv; break;
1897 case MOVT: res = (p.val & 0xFFFF) | ((sv & 0xFFFF) << 16); break;
1898 case SLL: res = p.val << sv; break;
1899 case SLR: res = p.val >> sv; break;
1900 case SAR: res = int64(p.val) >> sv; break;
1901 default: return false;
1902 }
1903 rvals.push_back(res);
1904 }
1905 set_multivals(&rvals, insn);
1906 return true;
1907}
1908
1909//-------------------------------------------------------------------------
1910inline void reg_value_base_t::perform_binary_op_for_nums(
1911 const reg_value_base_t &r,
1912 arith_op_t aop,
1913 const insn_t &insn)
1914{
1915 if ( is_num() && r.is_num() )
1916 {
1917 if ( perform_binary_op(r, aop, insn) )
1918 {
1919 state = NUMINSN;
1920 return;
1921 }
1922 }
1923 // not numbers or both THIS and R have multiple values
1924 set_unkinsn(insn);
1925}
1926
1927//-------------------------------------------------------------------------
1928inline void reg_value_base_t::add(
1929 const reg_value_base_t &r,
1930 const insn_t &insn)
1931{
1932 if ( is_spd() && r.is_num() // spd + num -> spd
1933 || is_num() && r.is_spd() // num + spd -> spd
1934 || is_num() && r.is_num() ) // num + num -> num
1935 {
1936 if ( perform_binary_op(r, ADD, insn) )
1937 {
1938 state = is_spd() || r.is_spd() ? SPDINSN : NUMINSN;
1939 return;
1940 }
1941 }
1942 // spd + spd or unknown or both THIS and R have multiple values
1943 set_unkinsn(insn);
1944}
1945
1946//-------------------------------------------------------------------------
1947inline void reg_value_base_t::sub(
1948 const reg_value_base_t &r,
1949 const insn_t &insn)
1950{
1951 if ( is_spd() && r.is_num() // spd - num -> spd
1952 || is_spd() && r.is_spd() // spd - spd -> num
1953 || is_num() && r.is_num() ) // num - num -> num
1954 {
1955 if ( perform_binary_op(r, SUB, insn) )
1956 {
1957 state = is_spd() && r.is_num() ? SPDINSN : NUMINSN;
1958 return;
1959 }
1960 }
1961 // num - spd or unknown or both THIS and R have multiple values
1962 set_unkinsn(insn);
1963}
1964
1965//-------------------------------------------------------------------------
1966inline void reg_value_base_t::bor(
1967 const reg_value_base_t &r,
1968 const insn_t &insn)
1969{
1970 return perform_binary_op_for_nums(r, OR, insn);
1971}
1972
1973//-------------------------------------------------------------------------
1974inline void reg_value_base_t::band(
1975 const reg_value_base_t &r,
1976 const insn_t &insn)
1977{
1978 if ( (is_spd() && r.is_mask()) || (is_num() && r.is_num()) )
1979 {
1980 if ( perform_binary_op(r, AND, insn) )
1981 {
1982 state = NUMINSN;
1983 return;
1984 }
1985 }
1986 // not numbers or not mask of SPD or both THIS and R have multiple values
1987 set_unkinsn(insn);
1988}
1989
1990//-------------------------------------------------------------------------
1991inline void reg_value_base_t::bxor(
1992 const reg_value_base_t &r,
1993 const insn_t &insn)
1994{
1995 return perform_binary_op_for_nums(r, XOR, insn);
1996}
1997
1998//-------------------------------------------------------------------------
1999inline void reg_value_base_t::bandnot(
2000 const reg_value_base_t &r,
2001 const insn_t &insn)
2002{
2003 if ( (is_spd() && r.is_mask()) || (is_num() && r.is_num()) )
2004 {
2005 if ( perform_binary_op(r, AND_NOT, insn) )
2006 {
2007 state = is_spd() ? SPDINSN : NUMINSN;
2008 return;
2009 }
2010 }
2011 // not numbers or not SPD aligning or both THIS and R have multiple values
2012 set_unkinsn(insn);
2013}
2014
2015//-------------------------------------------------------------------------
2016inline void reg_value_base_t::sll(
2017 const reg_value_base_t &r,
2018 const insn_t &insn)
2019{
2020 return perform_binary_op_for_nums(r, SLL, insn);
2021}
2022
2023//-------------------------------------------------------------------------
2024inline void reg_value_base_t::slr(
2025 const reg_value_base_t &r,
2026 const insn_t &insn)
2027{
2028 return perform_binary_op_for_nums(r, SLR, insn);
2029}
2030
2031//-------------------------------------------------------------------------
2032inline void reg_value_base_t::sar(
2033 const reg_value_base_t &r,
2034 const insn_t &insn)
2035{
2036 return perform_binary_op_for_nums(r, SAR, insn);
2037}
2038
2039//-------------------------------------------------------------------------
2040inline void reg_value_base_t::movt(
2041 const reg_value_base_t &r,
2042 const insn_t &insn)
2043{
2044 return perform_binary_op_for_nums(r, MOVT, insn);
2045}
2046
2047//-------------------------------------------------------------------------
2048inline void reg_value_base_t::neg(const insn_t &insn)
2049{
2050 if ( is_num() )
2051 {
2052 qvector<uint64> rvals;
2053 rvals.reserve(vals.size());
2054 for ( auto &p : vals )
2055 rvals.push_back(0-p.val);
2056 set_multivals(&rvals, insn);
2057 state = NUMINSN;
2058 }
2059 else // not a number
2060 {
2061 set_unkinsn(insn);
2062 }
2063}
2064
2065//-------------------------------------------------------------------------
2066inline void reg_value_base_t::bnot(const insn_t &insn)
2067{
2068 if ( is_num() )
2069 {
2070 qvector<uint64> rvals;
2071 rvals.reserve(vals.size());
2072 for ( auto &p : vals )
2073 rvals.push_back(~p.val);
2074 set_multivals(&rvals, insn);
2075 state = NUMINSN;
2076 }
2077 else // not a number
2078 {
2079 set_unkinsn(insn);
2080 }
2081}
2082
2083//-------------------------------------------------------------------------
2084inline void reg_value_base_t::add_num(uint64 r, const insn_t &insn)
2085{
2086 if ( !is_known() || r == 0 )
2087 return;
2088 qvector<uint64> rvals;
2089 rvals.reserve(vals.size());
2090 for ( auto &p : vals )
2091 rvals.push_back(p.val + r);
2092 set_multivals(&rvals, insn);
2093 state = is_spd() ? SPDINSN : NUMINSN;
2094}
2095
2096//-------------------------------------------------------------------------
2097inline void reg_value_base_t::add_num(uint64 r)
2098{
2099 if ( !is_known() || r == 0 )
2100 return;
2101 for ( auto &p : vals )
2102 p.val += r;
2103 sort_multivals();
2104}
2105
2106//-------------------------------------------------------------------------
2107inline void reg_value_base_t::shift_left(uint64 r)
2108{
2109 if ( !is_known() || r == 0 )
2110 return;
2111 for ( auto &p : vals )
2112 p.val <<= r;
2113 sort_multivals();
2114}
2115
2116//-------------------------------------------------------------------------
2117inline void reg_value_base_t::shift_right(uint64 r, int nbytes)
2118{
2119 if ( !is_known() || r == 0 )
2120 return;
2121 for ( auto &p : vals )
2122 {
2123 if ( nbytes != 0 )
2124 {
2125 auto sv = static_cast<int64>(extend_sign(p.val, nbytes, true));
2126 p.val = sv >> r;
2127 }
2128 else
2129 {
2130 p.val >>= r;
2131 }
2132 }
2133 sort_multivals();
2134}
2135
2136//-------------------------------------------------------------------------
2137template<class V>
2138inline void reg_value_base_t::set_multivals(
2139 V *rvals,
2140 const insn_t &insn)
2141{
2142 // DEF_EA will be the same so it is enough to sort only VAL
2143 std::sort(rvals->begin(), rvals->end());
2144 size_t newsz = std::unique(rvals->begin(), rvals->end()) - rvals->begin();
2145 vals.resize(newsz);
2146 for ( size_t i = 0; i < newsz; ++i )
2147 vals[i] = val_def_t(rvals->at(i), insn);
2148}
2149
2150//-------------------------------------------------------------------------
2151inline void reg_value_base_t::sort_multivals()
2152{
2153 // at this point we use reg_value_def_t::operator<()
2154 std::sort(vals.begin(), vals.end());
2155 // at this point we use reg_value_def_t::operator==()
2156 size_t new_size = std::unique(vals.begin(), vals.end()) - vals.begin();
2157 vals.resize(new_size);
2158}
2159
2160//-------------------------------------------------------------------------
2161inline bool reg_value_base_t::get_num(uint64 *uval, int slotsize) const
2162{
2163 if ( slotsize == 0 || !is_num() || !is_value_unique() )
2164 return false;
2165 *uval = extend_sign(vals.begin()->val, slotsize, false);
2166 return true;
2167}
2168
2169//-------------------------------------------------------------------------
2170inline bool reg_value_base_t::get_addr(ea_t *addr, int addrsize) const
2171{
2172 if ( addrsize == 0 || !is_num() || !is_value_unique() )
2173 return false;
2174 *addr = extend_sign(vals.begin()->val, addrsize, false);
2175 return true;
2176}
2177
2178//-------------------------------------------------------------------------
2179inline bool reg_value_base_t::get_spd(sval_t *sval, int addrsize) const
2180{
2181 if ( addrsize == 0 || !is_spd() || !is_value_unique() )
2182 return false;
2183 *sval = extend_sign(vals.begin()->val, addrsize, true);
2184 return true;
2185}
2186
2187//-------------------------------------------------------------------------
2188inline void reg_value_base_t::extend(int width, bool is_signed)
2189{
2190 if ( !is_known() )
2191 return;
2192 for ( auto &p : vals )
2193 p.val = extend_sign(p.val, width, is_signed);
2194 sort_multivals();
2195}
2196
2197//-------------------------------------------------------------------------
2198inline void reg_value_base_t::truncate(
2199 int width,
2200 int slotsize,
2201 int addrsize)
2202{
2203 if ( !is_known() )
2204 return;
2205 bool is_signed = is_spd(); // SP delta is signed
2206 if ( width == 0 )
2207 {
2208 width = is_spd() ? addrsize : slotsize;
2209 if ( width == 0 )
2210 return;
2211 }
2212 for ( auto &p : vals )
2213 p.val = extend_sign(p.val, width, is_signed);
2214 sort_multivals();
2215}
2216
2217//-------------------------------------------------------------------------
2219{
2220 slotsize = rf->slotsize;
2221 addrsize = rf->addrsize;
2222}
2223
2224//-------------------------------------------------------------------------
2225inline reg_finder_op_t reg_finder_op_t::make_reg(int reg, int width)
2226{
2227 uint32 packed_width = pack_width(width);
2228 if ( packed_width == BADREG || !is_valid_reg(reg) )
2229 return rfop_t();
2230 return rfop_t(REG | packed_width | uint16(reg));
2231}
2232
2233//-------------------------------------------------------------------------
2234inline reg_finder_op_t reg_finder_op_t::make_stkoff(
2235 sval_t stkoff,
2236 int width)
2237{
2238 uint32 packed_width = pack_width(width);
2239 if ( packed_width == BADREG || !is_valid_stkoff(stkoff) )
2240 return rfop_t();
2241 bool negative = stkoff < 0;
2242 return rfop_t(STKVAR
2243 | packed_width
2244 | (negative ? STKOFF_SIGNBIT : 0)
2245 | uint32(negative ? -stkoff : stkoff));
2246}
2247
2248//-------------------------------------------------------------------------
2249inline void reg_finder_op_t::set_width(int width)
2250{
2251 uint32 packed_width = pack_width(width);
2252 if ( packed_width == BADREG )
2253 {
2254 clear();
2255 return;
2256 }
2257 packed &= ~WIDTH_MASK;
2258 packed |= packed_width;
2259}
2260
2261//-------------------------------------------------------------------------
2263{
2264 packed &= ~SIGNED;
2265 if ( is_signed )
2266 packed |= SIGNED;
2267}
2268
2269//-------------------------------------------------------------------------
2271{
2272 uint32 packed_width = pack_width(width);
2273 if ( packed_width == BADREG )
2274 {
2275 clear();
2276 return;
2277 }
2278 packed &= ~WIDTH_MASK;
2279 packed |= packed_width;
2280 packed &= ~SIGNED;
2281 if ( is_signed )
2282 packed |= SIGNED;
2283}
2284
2285//-------------------------------------------------------------------------
2287{
2288 switch ( width )
2289 {
2290 case 1: return 0 << WIDTH_SHIFT; break;
2291 case 2: return 1 << WIDTH_SHIFT; break;
2292 case 4: return 2 << WIDTH_SHIFT; break;
2293 case 8: return 3 << WIDTH_SHIFT; break;
2294 default: return BADREG;
2295 }
2296}
2297
2298//-------------------------------------------------------------------------
2300{
2301 return int(get_dtype_size(op.dtype));
2302}
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:2262
void reserve(size_t cnt)
Increase the capacity of the qvector.
Definition pro.h:2605
void swap(qvector< T > &r) noexcept
Replace all attributes of this qvector with that of 'r', and vice versa.
Definition pro.h:2634
void qclear(void)
Destroy all elements but do not free memory.
Definition pro.h:2505
iterator end(void)
Get an iterator that points to the end of the qvector (NOT the last element)
Definition pro.h:2684
iterator begin(void)
Get an iterator that points to the first element in the qvector.
Definition pro.h:2683
void push_back(T &&x)
Append a new element to the end the qvector with a move semantics.
Definition pro.h:2432
size_t size(void) const
Get the number of elements in the qvector.
Definition pro.h:2494
idaman DEPRECATED sval_t ida_export get_spd(func_t *pfn, ea_t ea)
Get difference between the initial and current values of ESP.
THREAD_SAFE constexpr bool idaapi is_unknown(flags64_t F)
Does flag denote unexplored byte?
Definition bytes.hpp:786
bool function_contains(ea_t func_ea, ea_t ea)
Does the function at func_ea contain ea?
Definition funcs.hpp:1121
bool is_same_func(ea_t ea1, ea_t ea2)
Do two addresses belong to the same function?
Definition funcs.hpp:1128
idaman bool ida_export get_fchunk_info(fchunk_info_t *out, ea_t ea)
Get the range of the function chunk (entry or tail) containing 'ea'.
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:11173
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:13470
int inf_get_effective_addrsize()
Definition ida.hpp:686
Contains definition of the interface to IDP modules.
int nbytes
Definition kernwin.hpp:3037
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:350
unsigned int uint32
unsigned 32 bit value
Definition pro.h:352
qvector< uval_t > uvalvec_t
vector of unsigned values
Definition pro.h:2836
adiff_t sval_t
signed value used by the processor.
Definition pro.h:450
uint64 ea_t
Definition pro.h:425
int int32
signed 32 bit value
Definition pro.h:351
unsigned char uchar
unsigned 8 bit value
Definition pro.h:341
THREAD_SAFE void qswap(T &a, T &b)
Swap 2 objects of the same type using memory copies.
Definition pro.h:1728
qvector< ea_t > eavec_t
vector of addresses
Definition pro.h:2838
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:348
constexpr bool is_pow2(T val)
is power of 2? (or zero)
Definition pro.h:1435
_qstring< char > qstring
regular string
Definition pro.h:3771
int compare(const T &a, const T &b)
Definition pro.h:4607
unsigned int
Definition pronet.h:99
constexpr bool operator<(qpair< F, S > const &a, qpair< F, S > const &b)
Definition qpair.hpp:108
void swap(qpair< F, S > &a, qpair< F, S > &b) noexcept(noexcept(a.swap(b)))
Definition qpair.hpp:78
constexpr bool operator==(qpair< F, S > const &a, qpair< F, S > const &b)
Definition qpair.hpp:98
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).
idaman int ida_export reg_finder94_find_nearest_rvi(reg_value_info_t *rvi, ea_t ea, const int reg[2])
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_DEF_HELPERS(idaman) struct reg_value_def_t
the register value and its defining instruction
Definition regfinder.hpp:56
idaman bool ida_export find_regname_value_info(reg_value_info_t *rvi, ea_t ea, const char *regname, int max_depth=0)
Find register value using the register tracker.
idaman bool ida_export reg_finder94_find_reg_value_info(reg_value_info_t *out, ea_t ea, int reg, int max_depth)
DECLARE_TYPE_AS_MOVABLE(reg_value_def_t)
void(* reg_finder_binary_ops_adjust_fun)(reg_value_base_t *v1, reg_value_base_t *v2, const insn_t &insn, void *ud)
Definition regfinder.hpp:903
idaman int ida_export find_reg_value(uint64 *uval, ea_t ea, int reg)
Find register value using the register tracker.
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
DECLARE_REG_VALUE_BASE_HELPERS(idaman) struct reg_value_base_t
the value in a register after emulating instructions (base class)
Definition regfinder.hpp:136
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.
Definition regfinder.hpp:1789
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 regfinder.hpp:1833
Definition idp.hpp:2265
Base class for an range.
Definition range.hpp:35
Definition regfinder.hpp:818
void set_width_signness(int width, bool is_signed)
Definition regfinder.hpp:2270
rfop_t & operator=(const rfop_t &r)=default
bool empty() const
Definition regfinder.hpp:850
void set_width(int width)
Definition regfinder.hpp:2249
static bool is_valid_reg(int reg)
Definition regfinder.hpp:853
uint16 get_reg() const
Definition regfinder.hpp:878
void set_signness(bool is_signed)
Definition regfinder.hpp:2262
reg_finder_op_t(const rfop_t &r)=default
void clear()
Definition regfinder.hpp:851
reg_finder_op_t()
Definition regfinder.hpp:844
static reg_finder_op_t make_reg(int reg, int width)
Definition regfinder.hpp:2225
static bool is_valid_stkoff(sval_t stkoff)
Definition regfinder.hpp:859
int get_width() const
Definition regfinder.hpp:873
static reg_finder_op_t make_stkoff(sval_t stkoff, int width)
Definition regfinder.hpp:2234
reg_finder_op_t rfop_t
Definition regfinder.hpp:843
static uint32 pack_width(int width)
Definition regfinder.hpp:2286
bool is_reg() const
Definition regfinder.hpp:870
sval_t get_stkoff() const
Definition regfinder.hpp:879
DECLARE_COMPARISONS(reg_finder_op_t)
Definition regfinder.hpp:887
bool is_signed() const
Definition regfinder.hpp:872
static int get_op_width(const op_t &op)
Definition regfinder.hpp:2299
bool is_stkvar() const
Definition regfinder.hpp:871
bool is_reg(int reg) const
Definition regfinder.hpp:885
Definition regfinder.hpp:1005
cond_t(uchar cond=AL, uchar kind=NONE)
Definition regfinder.hpp:1041
uchar get_kind() const
Definition regfinder.hpp:1057
@ JUMPS
Definition regfinder.hpp:1038
@ NONE
Definition regfinder.hpp:1036
@ MODIFIES_CC
Definition regfinder.hpp:1037
bool jumps() const
Definition regfinder.hpp:1062
@ LE
Definition regfinder.hpp:1029
@ VC
Definition regfinder.hpp:1023
@ NV
Definition regfinder.hpp:1031
@ AL
Definition regfinder.hpp:1030
@ CC
Definition regfinder.hpp:1019
@ HI
Definition regfinder.hpp:1024
@ EQ
Definition regfinder.hpp:1016
@ CS
Definition regfinder.hpp:1018
@ LS
Definition regfinder.hpp:1025
@ MI
Definition regfinder.hpp:1020
@ LT
Definition regfinder.hpp:1027
@ PL
Definition regfinder.hpp:1021
@ VS
Definition regfinder.hpp:1022
@ GE
Definition regfinder.hpp:1026
@ NE
Definition regfinder.hpp:1017
@ GT
Definition regfinder.hpp:1028
bool modifies_cond_codes() const
Definition regfinder.hpp:1061
uchar get_cond() const
Definition regfinder.hpp:1044
bool is_included_in(cond_t r) const
Definition regfinder.hpp:1048
Definition regfinder.hpp:1325
void handle_delay_slot()
Definition regfinder.hpp:1332
bool has_delay_slot() const
Definition regfinder.hpp:1328
bool operator<(const flow_t &r) const
Definition regfinder.hpp:1345
ea_t ds
Definition regfinder.hpp:1327
flow_t(ea_t _ea, ea_t _ds=BADADDR)
Definition regfinder.hpp:1334
ea_t ea
Definition regfinder.hpp:1326
bool is_ea_handled() const
Definition regfinder.hpp:1330
ea_t actual_ea() const
Definition regfinder.hpp:1342
Definition regfinder.hpp:1415
bool is_signed
Definition regfinder.hpp:1429
sval_t delta
Definition regfinder.hpp:1435
const op_t * src_op
Definition regfinder.hpp:1426
rfop_t new_rfop
Definition regfinder.hpp:1418
const op_t * dst_op
Definition regfinder.hpp:1424
Definition regfinder.hpp:931
bool does_call_spoil_stkvars() const
Definition regfinder.hpp:960
const procmod_t & pm
Definition regfinder.hpp:932
void calc_op_addr(rvb_t *addr, const op_t &memop, const insn_t &insn, flow_t flow)
Definition regfinder.hpp:1515
virtual cond_t get_cond(ea_t ea) const
Definition regfinder.hpp:1364
rvi_t find_op_addr(const op_t &memop, const insn_t &insn, int max_depth=0)
Definition regfinder.hpp:1278
void emulate_unary_op(rvb_t *value, rvb_t::arith_op_t aop, int reg, const insn_t &insn, flow_t flow)
Definition regfinder.hpp:1547
size_t linear_flow_cnt
Definition regfinder.hpp:985
reg_value_info_t rvi_t
Definition regfinder.hpp:970
virtual bool is_funcwide_reg(ea_t ea, int reg) const
Definition regfinder.hpp:1401
bool update_sizes(int _slotsize=0)
Definition regfinder.hpp:1142
virtual rvb_t handle_well_known_regs(flow_t flow, rfop_t rfop, bool is_func_start) const
Definition regfinder.hpp:1374
friend struct reg_finder_chainvec_t
Definition regfinder.hpp:1068
friend struct reg_finder_block_t
Definition regfinder.hpp:975
friend struct reg_finder_pred_t
Definition regfinder.hpp:976
reg_finder_block_t block_t
Definition regfinder.hpp:973
friend struct reg_finder_xrefs_cache_t
Definition regfinder.hpp:1113
reg_finder_t(const procmod_t &_pm, int _proc_maxop=3, uint32 _flags=RF_DOES_CALL_SPOIL_STKVARS)
Definition regfinder.hpp:1124
size_t bblk_cnt
Definition regfinder.hpp:992
bool may_modify_stkvar(rvb_t *value, rfop_t rfop, const insn_t &insn)
Definition regfinder.hpp:1583
virtual int get_sp_reg(ea_t ea) const
Definition regfinder.hpp:1394
int find_nearest(reg_value_info_t *rvi, ea_t ea, const int reg[2], size_t linear_insns=10)
Definition regfinder.hpp:1204
bool find_const(uint64 *val, ea_t ea, rfop_t rfop, int max_depth=0)
Definition regfinder.hpp:1229
static constexpr uint32 RF_ALLOW_XREFS_CACHE
Definition regfinder.hpp:958
ea_t aborting_ea
Definition regfinder.hpp:991
op_t fake_op1
Definition regfinder.hpp:999
bool can_resolve_mem(ea_t ea) const
Definition regfinder.hpp:1314
int addrsize
Definition regfinder.hpp:936
const int proc_maxop
Definition regfinder.hpp:933
uint32 flags
Definition regfinder.hpp:934
virtual bool is_mem_readonly(ea_t) const
Definition regfinder.hpp:1388
virtual flow_t process_delay_slot(ea_t ea, cref_t) const
Definition regfinder.hpp:1358
bool find_addr(ea_t *addr, ea_t ea, rfop_t rfop, int max_depth=0)
Definition regfinder.hpp:1236
void invalidate_cache()
Definition regfinder.hpp:1162
virtual bool emulate_insn(rvb_t *value, const rfop_t &rfop, const insn_t &insn, flow_t flow)
Definition regfinder.hpp:1467
bool only_linear_flow() const
Definition regfinder.hpp:987
size_t initial_block_idx
Definition regfinder.hpp:980
static constexpr size_t NO_CHAIN
Definition regfinder.hpp:996
friend struct reg_finder_rfop_chains_t
Definition regfinder.hpp:1104
reg_finder_op_t rfop_t
Definition regfinder.hpp:972
void invalidate_xrefs_cache(ea_t ea, dref_t dref)
Definition regfinder.hpp:1169
void emulate_mem_read(rvb_t *value, const rvb_t &addr, int width, bool is_signed, const insn_t &insn)
Definition regfinder.hpp:1301
virtual ~reg_finder_t()
Definition regfinder.hpp:1138
rfop_t make_rfop(const op_t &_op, const insn_t &insn, ea_t func_ea)
Definition regfinder.hpp:1257
bool fixed_max_depth
Definition regfinder.hpp:981
int slotsize
Definition regfinder.hpp:937
ea_t cur_func_ea
Definition regfinder.hpp:979
void emulate_binary_op_shifted(rvb_t *value, rvb_t::arith_op_t aop, const op_t &op1, const op_t &op2, int width, bool is_signed, rvb_t::arith_op_t shift, uint8 shift_count, const insn_t &insn, flow_t flow)
Definition regfinder.hpp:1560
rvb_t find(flow_t flow, int reg)
Definition regfinder.hpp:1505
static constexpr uint32 RF_DOES_CALL_SPOIL_STKVARS
Definition regfinder.hpp:953
virtual bool can_track_op(op_t *op, const insn_t &insn, ea_t func_ea) const
Definition regfinder.hpp:1482
bool allow_xrefs_cache() const
Definition regfinder.hpp:964
bool find_spd(sval_t *spval, ea_t ea, int reg=-1, int max_depth=-1)
Definition regfinder.hpp:1243
int cur_call_depth
Definition regfinder.hpp:984
void invalidate_cache(ea_t to, ea_t from, cref_t cref)
Definition regfinder.hpp:1157
int cur_max_depth
Definition regfinder.hpp:983
rvb_t standalone_value
Definition regfinder.hpp:993
rvi_t find(ea_t ea, rfop_t rfop, int max_depth=0, size_t linear_insns=0)
Definition regfinder.hpp:1189
friend struct reg_finder_debug_t
Definition regfinder.hpp:1319
virtual bool is_move_insn(move_desc_t *move_desc, const rfop_t &rfop, const insn_t &insn)
Definition regfinder.hpp:1442
rvb_t find(flow_t flow, rfop_t rfop)
Definition regfinder.hpp:1495
void emulate_binary_op(rvb_t *value, rvb_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:1530
virtual bool can_track_op93(op_t *op, const insn_t &insn, range_t *pfn) const
Definition regfinder.hpp:1408
reg_value_base_t rvb_t
Definition regfinder.hpp:971
op_t fake_op2
Definition regfinder.hpp:1000
static int get_effective_addrsize()
Definition regfinder.hpp:946
reg_finder_pred_t pred_t
Definition regfinder.hpp:974
Definition regfinder.hpp:733
bool get_addr(ea_t *addr) const
Return the address if the value is a constant (truncated to ADDRSIZE).
Definition regfinder.hpp:774
reg_value_info_t(reg_value_base_t &&base, int _slotsize, int _addrsize)
Definition regfinder.hpp:747
void trunc_uval(const procmod_t &pm)
Definition regfinder.hpp:800
void set_context(int _slotsize, int _addrsize)
Set the context.
Definition regfinder.hpp:758
bool get_num(uint64 *uval) const
Return the number if the value is a constant (truncated to SLOTSIZE).
Definition regfinder.hpp:767
void truncate(int width=0)
Truncate the value to WIDTH (in bytes).
Definition regfinder.hpp:794
bool get_spd(sval_t *sval) const
Return the SP delta if the value depends on the stack pointer (sign-extended to ADDRSIZE).
Definition regfinder.hpp:784
int addrsize
Definition regfinder.hpp:736
reg_value_info_t()
Definition regfinder.hpp:739
reg_value_info_t(const reg_value_base_t &base, int _slotsize, int _addrsize)
Definition regfinder.hpp:740
int slotsize
Definition regfinder.hpp:735
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.