1 /* radare - LGPL - Copyright 2014-2019 - pancake */
2 
3 #include <r_reg.h>
4 
5 #undef Z
6 #undef S
7 #undef C
8 #undef O
9 #undef P
10 #define Z f->z
11 #define S f->s
12 #define C f->c
13 #define O f->o
14 #define P f->p
15 
r_reg_cond_get(RReg * reg,const char * name)16 R_API RRegItem *r_reg_cond_get(RReg *reg, const char *name) {
17 	int i = R_REG_TYPE_GPR;
18 	RListIter *iter;
19 	RRegItem *r;
20 	r_return_val_if_fail (reg && name, NULL);
21 
22 	r_list_foreach (reg->regset[i].regs, iter, r) {
23 		if (r->flags && !strcmp (name, r->flags)) {
24 			return r;
25 		}
26 	}
27 	return NULL;
28 }
29 
r_reg_cond_get_value(RReg * r,const char * name)30 R_API int r_reg_cond_get_value(RReg *r, const char *name) {
31 	return (int)r_reg_get_value (r, r_reg_cond_get (r, name)) ? 1 : 0;
32 }
33 
r_reg_cond_set(RReg * r,const char * name,bool val)34 R_API bool r_reg_cond_set(RReg *r, const char *name, bool val) {
35 	RRegItem *item = r_reg_cond_get (r, name);
36 	if (item) {
37 		r_reg_set_value (r, item, val);
38 		return true;
39 	}
40 	// eprintf ("Cannot find '%s'\n", name);
41 	return false;
42 }
43 
r_reg_cond_to_string(int n)44 R_API const char *r_reg_cond_to_string(int n) {
45 	const char *cs[] = {
46 		"eq", "ne", "cf", "neg", "of", "hi", "he",
47 		"lo", "loe", "ge", "gt", "lt", "le"
48 	};
49 	if (n < 0 || (n > (sizeof (cs) / sizeof (*cs)) - 1)) {
50 		return NULL;
51 	}
52 	return cs[n];
53 }
54 
r_reg_cond_from_string(const char * str)55 R_API int r_reg_cond_from_string(const char *str) {
56 	if (!strcmp (str, "eq")) {
57 		return R_REG_COND_EQ;
58 	}
59 	if (!strcmp (str, "ne")) {
60 		return R_REG_COND_NE;
61 	}
62 	if (!strcmp (str, "cf")) {
63 		return R_REG_COND_CF;
64 	}
65 	if (!strcmp (str, "neg")) {
66 		return R_REG_COND_NEG;
67 	}
68 	if (!strcmp (str, "of")) {
69 		return R_REG_COND_OF;
70 	}
71 	if (!strcmp (str, "hi")) {
72 		return R_REG_COND_HI;
73 	}
74 	if (!strcmp (str, "he")) {
75 		return R_REG_COND_HE;
76 	}
77 	if (!strcmp (str, "lo")) {
78 		return R_REG_COND_LO;
79 	}
80 	if (!strcmp (str, "loe")) {
81 		return R_REG_COND_LOE;
82 	}
83 	if (!strcmp (str, "ge")) {
84 		return R_REG_COND_GE;
85 	}
86 	if (!strcmp (str, "gt")) {
87 		return R_REG_COND_GT;
88 	}
89 	if (!strcmp (str, "lt")) {
90 		return R_REG_COND_LT;
91 	}
92 	if (!strcmp (str, "le")) {
93 		return R_REG_COND_LE;
94 	}
95 	// TODO: move this into core
96 	eprintf ("| Usage: drc[=] [condition](=1,0)\n"
97 		 "| eq    equal\n"
98 		 "| ne    not equal\n"
99 		 "| cf    carry flag set\n"
100 		 "| neg   negative value (has sign)\n"
101 		 "| of    overflow\n"
102 		 "|unsigned:\n"
103 		 "| hi    higher\n"
104 		 "| he    higher or equal\n"
105 		 "| lo    lower\n"
106 		 "| loe   lower or equal\n"
107 		 "|signed:\n"
108 		 "| ge    greater or equal\n"
109 		 "| gt    greater than\n"
110 		 "| le    less or equal\n"
111 		 "| lt    less than\n");
112 	return -1;
113 }
114 
r_reg_cond_bits(RReg * r,int type,RRegFlags * f)115 R_API int r_reg_cond_bits(RReg *r, int type, RRegFlags *f) {
116 	switch (type) {
117 	case R_REG_COND_EQ: return Z;
118 	case R_REG_COND_NE: return !Z;
119 	case R_REG_COND_CF: return C;
120 	case R_REG_COND_NEG: return S;
121 	case R_REG_COND_OF:
122 		return O;
123 	// unsigned
124 	case R_REG_COND_HI: return (!Z && C); // HIGHER
125 	case R_REG_COND_HE: return Z || (!Z && C); // HIGHER OR EQUAL
126 	case R_REG_COND_LO: return (Z || !C); // LOWER
127 	case R_REG_COND_LOE:
128 		return (Z || !C); // LOWER OR EQUAL
129 	// signed
130 	case R_REG_COND_GE: return ((S && O) || (!S && !O));
131 	case R_REG_COND_GT: return ((S && !Z && O) || (!S && !Z && !O));
132 	case R_REG_COND_LT: return ((S && !O) || (!S && O));
133 	case R_REG_COND_LE: return (Z || (S && !O) || (!S && O));
134 	}
135 	return false;
136 }
137 
r_reg_cond_bits_set(RReg * r,int type,RRegFlags * f,bool v)138 R_API bool r_reg_cond_bits_set(RReg *r, int type, RRegFlags *f, bool v) {
139 	switch (type) {
140 	case R_REG_COND_EQ: Z = v; break;
141 	case R_REG_COND_NE: Z = !v; break;
142 	case R_REG_COND_CF: C = v; break;
143 	case R_REG_COND_NEG: S = v; break;
144 	case R_REG_COND_OF: O = v; break;
145 	case R_REG_COND_HI:
146 		if (v) {
147 			Z = 0;
148 			C = 1;
149 		} else {
150 			Z = 1;
151 			C = 0;
152 		}
153 		break;
154 	case R_REG_COND_HE:
155 		if (v) {
156 			Z = 1;
157 		} else {
158 			Z = 0;
159 			C = 1;
160 		}
161 		break;
162 	case R_REG_COND_LO:
163 		if (v) {
164 			Z = 1;
165 			C = 0;
166 		} else {
167 			Z = 0;
168 			C = 1;
169 		}
170 		break;
171 	case R_REG_COND_LOE:
172 		if (v) {
173 			Z = 1;
174 			C = 0;
175 		} else {
176 			Z = 0;
177 			C = 1;
178 		}
179 		break;
180 	// signed
181 	case R_REG_COND_GE:
182 		if (v) {
183 			S = O = 1;
184 		} else {
185 			S = 1;
186 			O = 0;
187 		}
188 		break;
189 	case R_REG_COND_GT:
190 		if (v) {
191 			S = 1;
192 			Z = 0;
193 			O = 1;
194 		} else {
195 			S = 0;
196 			Z = 1;
197 			O = 0;
198 		}
199 		break;
200 	case R_REG_COND_LT:
201 		if (v) {
202 			S = 1;
203 			O = 0;
204 		} else {
205 			S = 1;
206 			O = 1;
207 		}
208 		break;
209 	case R_REG_COND_LE:
210 		if (v) {
211 			S = 0;
212 			Z = 1;
213 			O = 0;
214 		} else {
215 			S = 1;
216 			Z = 0;
217 			O = 1;
218 		}
219 		break;
220 	default:
221 		return false;
222 	}
223 	return true;
224 }
225 
r_reg_cond(RReg * r,int type)226 R_API int r_reg_cond(RReg *r, int type) {
227 	RRegFlags f = { 0 };
228 	r_reg_cond_retrieve (r, &f);
229 	return r_reg_cond_bits (r, type, &f);
230 }
231 
r_reg_cond_retrieve(RReg * r,RRegFlags * f)232 R_API RRegFlags *r_reg_cond_retrieve(RReg *r, RRegFlags *f) {
233 	if (!f) {
234 		f = R_NEW0 (RRegFlags);
235 	}
236 	if (!f) {
237 		return NULL;
238 	}
239 	f->s = r_reg_cond_get_value (r, "sign"); // sign, negate flag, less than zero
240 	f->z = r_reg_cond_get_value (r, "zero"); // zero flag
241 	f->c = r_reg_cond_get_value (r, "carry"); // carry flag
242 	f->o = r_reg_cond_get_value (r, "overflow"); // overflow flag
243 	f->p = r_reg_cond_get_value (r, "parity"); // parity // intel only
244 	return f;
245 }
246 
r_reg_cond_apply(RReg * r,RRegFlags * f)247 R_API void r_reg_cond_apply(RReg *r, RRegFlags *f) {
248 	r_return_if_fail (r && f);
249 	r_reg_cond_set (r, "sign", f->s);
250 	r_reg_cond_set (r, "zero", f->z);
251 	r_reg_cond_set (r, "carry", f->c);
252 	r_reg_cond_set (r, "overflow", f->o);
253 	r_reg_cond_set (r, "parity", f->p);
254 }
255