1 /* radare - LGPL - Copyright 2009-2019 - pancake */
2 
3 #include <r_reg.h>
4 #include <r_util.h>
5 
6 typedef ut32 ut27;
r_read_me27(const ut8 * buf,int boff)7 static ut27 r_read_me27(const ut8 *buf, int boff) {
8 	ut27 ret = 0;
9 	r_mem_copybits_delta ((ut8 *)&ret, 18, buf, boff, 9);
10 	r_mem_copybits_delta ((ut8 *)&ret, 9, buf, boff + 9, 9);
11 	r_mem_copybits_delta ((ut8 *)&ret, 0, buf, boff + 18, 9);
12 	return ret;
13 }
14 
r_reg_get_value_big(RReg * reg,RRegItem * item,utX * val)15 R_API ut64 r_reg_get_value_big(RReg *reg, RRegItem *item, utX *val) {
16 	r_return_val_if_fail (reg && item, 0);
17 
18 	ut64 ret = 0LL;
19 	int off = BITS2BYTES (item->offset);
20 	RRegSet *regset = &reg->regset[item->arena];
21 	if (!regset->arena) {
22 		return 0LL;
23 	}
24 	switch (item->size) {
25 	case 80: // word + qword
26 		if (regset->arena->bytes && (off + 10 <= regset->arena->size)) {
27 			val->v80.Low = *((ut64 *)(regset->arena->bytes + off));
28 			val->v80.High = *((ut16 *)(regset->arena->bytes + off + 8));
29 		} else {
30 			eprintf ("r_reg_get_value: null or oob arena for current regset\n");
31 		}
32 		ret = val->v80.Low;
33 		break;
34 	case 96: // dword + qword
35 		if (regset->arena->bytes && (off + 12 <= regset->arena->size)) {
36 			val->v96.Low = *((ut64 *)(regset->arena->bytes + off));
37 			val->v96.High = *((ut32 *)(regset->arena->bytes + off + 8));
38 		} else {
39 			eprintf ("r_reg_get_value: null or oob arena for current regset\n");
40 		}
41 		ret = val->v96.Low;
42 		break;
43 	case 128: // qword + qword
44 		if (regset->arena->bytes && (off + 16 <= regset->arena->size)) {
45 			val->v128.Low = *((ut64 *)(regset->arena->bytes + off));
46 			val->v128.High = *((ut64 *)(regset->arena->bytes + off + 8));
47 		} else {
48 			eprintf ("r_reg_get_value: null or oob arena for current regset\n");
49 		}
50 		ret = val->v128.Low;
51 		break;
52 	case 256:// qword + qword + qword + qword
53 		if (regset->arena->bytes && (off + 32 <= regset->arena->size)) {
54 			val->v256.Low.Low = *((ut64 *)(regset->arena->bytes + off));
55 			val->v256.Low.High = *((ut64 *)(regset->arena->bytes + off + 8));
56 			val->v256.High.Low = *((ut64 *)(regset->arena->bytes + off + 16));
57 			val->v256.High.High = *((ut64 *)(regset->arena->bytes + off + 24));
58 		} else {
59 			eprintf ("r_reg_get_value: null or oob arena for current regset\n");
60 		}
61 		ret = val->v256.Low.Low;
62 		break;
63 	default:
64 		eprintf ("r_reg_get_value_big: Bit size %d not supported\n", item->size);
65 		break;
66 	}
67 	return ret;
68 }
69 
r_reg_get_value(RReg * reg,RRegItem * item)70 R_API ut64 r_reg_get_value(RReg *reg, RRegItem *item) {
71 	r_return_val_if_fail (reg && item, 0);
72 	if (!reg || !item || item->offset == -1) {
73 		return 0LL;
74 	}
75 	int off = BITS2BYTES (item->offset);
76 	RRegSet *regset = &reg->regset[item->arena];
77 	if (!regset->arena) {
78 		return 0LL;
79 	}
80 	switch (item->size) {
81 	case 1: {
82 		int offset = item->offset / 8;
83 		if (offset >= regset->arena->size) {
84 			break;
85 		}
86 		return (regset->arena->bytes[offset] &
87 			       (1 << (item->offset % 8)))
88 			? 1
89 			: 0;
90 	} break;
91 	case 4:
92 		if (regset->arena->size - off - 1 >= 0) {
93 			return (r_read_at_ble8 (regset->arena->bytes, off)) & 0xF;
94 		}
95 		break;
96 	case 8:
97 		if (regset->arena->size - off - 1 >= 0) {
98 			return r_read_at_ble8 (regset->arena->bytes, off);
99 		}
100 		break;
101 	case 16:
102 		if (regset->arena->size - off - 2 >= 0) {
103 			return r_read_ble16 (regset->arena->bytes + off, reg->big_endian);
104 		}
105 		break;
106 	case 27:
107 		if (off + 3 < regset->arena->size) {
108 			return r_read_me27 (regset->arena->bytes + off, 0);
109 		}
110 		break;
111 	case 32:
112 		if (off + 4 <= regset->arena->size) {
113 			return r_read_ble32 (regset->arena->bytes + off, reg->big_endian);
114 		}
115 		eprintf ("r_reg_get_value: 32bit oob read %d\n", off);
116 		break;
117 	case 64:
118 		if (regset->arena && regset->arena->bytes && (off + 8 <= regset->arena->size)) {
119 			return r_read_ble64 (regset->arena->bytes + off, reg->big_endian);
120 		}
121 		//eprintf ("r_reg_get_value: null or oob arena for current regset\n");
122 		break;
123 	case 80: // long double
124 	case 96: // long floating value
125 		// FIXME: It is a precision loss, please implement me properly!
126 		return (ut64)r_reg_get_longdouble (reg, item);
127 	case 128:
128 	case 256:
129 		// XXX 128 & 256 bit
130 		return (ut64)r_reg_get_longdouble (reg, item);
131 	default:
132 		eprintf ("r_reg_get_value: Bit size %d not supported\n", item->size);
133 		break;
134 	}
135 	return 0LL;
136 }
137 
r_reg_get_value_by_role(RReg * reg,RRegisterId role)138 R_API ut64 r_reg_get_value_by_role(RReg *reg, RRegisterId role) {
139 	// TODO use mapping from RRegisterId to RRegItem (via RRegSet)
140 	return r_reg_get_value (reg, r_reg_get (reg, r_reg_get_name (reg, role), -1));
141 }
142 
r_reg_set_value(RReg * reg,RRegItem * item,ut64 value)143 R_API bool r_reg_set_value(RReg *reg, RRegItem *item, ut64 value) {
144 	ut8 bytes[12];
145 	ut8 *src = bytes;
146 	r_return_val_if_fail (reg && item, false);
147 
148 	if (r_reg_is_readonly (reg, item)) {
149 		return true;
150 	}
151 	if (item->offset < 0) {
152 		return true;
153 	}
154 	RRegArena *arena = reg->regset[item->arena].arena;
155 	if (!arena) {
156 		return false;
157 	}
158 	switch (item->size) {
159 	case 80:
160 	case 96: // long floating value
161 		r_reg_set_longdouble (reg, item, (long double)value);
162 		break;
163 	case 64:
164 		if (reg->big_endian) {
165 			r_write_be64 (src, value);
166 		} else {
167 			r_write_le64 (src, value);
168 		}
169 		break;
170 	case 32:
171 		if (reg->big_endian) {
172 			r_write_be32 (src, value);
173 		} else {
174 			r_write_le32 (src, value);
175 		}
176 		break;
177 	case 16:
178 		if (reg->big_endian) {
179 			r_write_be16 (src, value);
180 		} else {
181 			r_write_le16 (src, value);
182 		}
183 		break;
184 	case 8:
185 		r_write_ble8 (src, (ut8) (value & UT8_MAX));
186 		break;
187 	case 1:
188 		if (value) {
189 			ut8 *buf = arena->bytes + (item->offset / 8);
190 			int bit = (item->offset % 8);
191 			ut8 mask = (1 << bit);
192 			buf[0] = (buf[0] & (0xff ^ mask)) | mask;
193 		} else {
194 			int idx = item->offset / 8;
195 			if (idx + item->size > arena->size) {
196 				eprintf ("RRegSetOverflow %d vs %d\n", idx + item->size, arena->size);
197 				return false;
198 			}
199 			ut8 *buf = arena->bytes + idx;
200 			int bit = item->offset % 8;
201 			ut8 mask = 0xff ^ (1 << bit);
202 			buf[0] = (buf[0] & mask) | 0;
203 		}
204 		return true;
205 	case 128:
206 	case 256:
207 		// XXX 128 & 256 bit
208 		return false; // (ut64)r_reg_get_longdouble (reg, item);
209 	default:
210 		eprintf ("r_reg_set_value: Bit size %d not supported\n", item->size);
211 		return false;
212 	}
213 	const bool fits_in_arena = (arena->size - BITS2BYTES (item->offset) - BITS2BYTES (item->size)) >= 0;
214 	if (src && fits_in_arena) {
215 		r_mem_copybits (reg->regset[item->arena].arena->bytes +
216 				BITS2BYTES (item->offset),
217 				src, item->size);
218 		return true;
219 	}
220 	eprintf ("r_reg_set_value: Cannot set %s to 0x%" PFMT64x "\n", item->name, value);
221 	return false;
222 }
223 
r_reg_set_value_by_role(RReg * reg,RRegisterId role,ut64 val)224 R_API bool r_reg_set_value_by_role(RReg *reg, RRegisterId role, ut64 val) {
225 	// TODO use mapping from RRegisterId to RRegItem (via RRegSet)
226 	RRegItem *r = r_reg_get (reg, r_reg_get_name (reg, role), -1);
227 	return r_reg_set_value (reg, r, val);
228 }
229 
r_reg_set_bvalue(RReg * reg,RRegItem * item,const char * str)230 R_API ut64 r_reg_set_bvalue(RReg *reg, RRegItem *item, const char *str) {
231 	ut64 num = UT64_MAX;
232 	if (item && item->flags && str) {
233 		num = r_str_bits_from_string (str, item->flags);
234 		if (num == UT64_MAX) {
235 			num = r_num_math (NULL, str);
236 		}
237 		r_reg_set_value (reg, item, num);
238 	}
239 	return num;
240 }
241 
r_reg_get_bvalue(RReg * reg,RRegItem * item)242 R_API R_HEAP char *r_reg_get_bvalue(RReg *reg, RRegItem *item) {
243 	char *out = NULL;
244 	if (reg && item && item->flags) {
245 		out = malloc (strlen (item->flags) + 1);
246 		if (out) {
247 			ut64 num = r_reg_get_value (reg, item);
248 			r_str_bits (out, (ut8 *)&num,
249 				strlen (item->flags) * 8, item->flags);
250 		}
251 	}
252 	return out;
253 }
254 
255 /* packed registers */
256 // packbits can be 8, 16, 32 or 64
257 // result value is always casted into ut64
258 // TODO: support packbits=128 for xmm registers
r_reg_get_pack(RReg * reg,RRegItem * item,int packidx,int packbits)259 R_API ut64 r_reg_get_pack(RReg *reg, RRegItem *item, int packidx, int packbits) {
260 	r_return_val_if_fail (reg && item, 0LL);
261 
262 	if (packbits < 1) {
263 		packbits = item->packed_size;
264 	}
265 	if (packbits > 64) {
266 		packbits = 64;
267 		eprintf ("Does not support pack bits > 64\n");
268 	}
269 
270 	ut64 ret = 0LL;
271 	const int packbytes = packbits / 8;
272 	const int packmod = packbits % 8;
273 	if (packmod) {
274 		eprintf ("Invalid bit size for packet register\n");
275 		return 0LL;
276 	}
277 	if ((packidx + 1) * packbits > item->size) {
278 		eprintf ("Packed index is beyond the register size\n");
279 		return 0LL;
280 	}
281 	RRegSet *regset = &reg->regset[item->arena];
282 	if (!regset->arena) {
283 		return 0LL;
284 	}
285 	int off = BITS2BYTES (item->offset);
286 	off += (packidx * packbytes);
287 	if (regset->arena->size - off - 1 >= 0) {
288 		int i;
289 		for (i = packbytes - 1; i >= 0; i--) {
290 			ret = (ret << 8) | regset->arena->bytes[off + i];
291 		}
292 	}
293 	return ret;
294 }
295 
296 // TODO: support packbits=128 for xmm registers
r_reg_set_pack(RReg * reg,RRegItem * item,int packidx,int packbits,ut64 val)297 R_API int r_reg_set_pack(RReg *reg, RRegItem *item, int packidx, int packbits, ut64 val) {
298 	r_return_val_if_fail (reg && reg->regset->arena && item, false);
299 
300 	if (packbits < 1) {
301 		packbits = item->packed_size;
302 	}
303 	if (packbits > 64) {
304 		packbits = 64;
305 		eprintf ("Does not support pack bits > 64\n");
306 	}
307 
308 	int packbytes = packbits / 8;
309 	if ((packidx + 1) * packbits > item->size) {
310 		eprintf ("Packed index is beyond the register size\n");
311 		return false;
312 	}
313 	int off = BITS2BYTES (item->offset);
314 	off += (packidx * packbytes);
315 	if (reg->regset[item->arena].arena->size - BITS2BYTES (off) - BITS2BYTES (packbytes) >= 0) {
316 		ut8 *dst = reg->regset[item->arena].arena->bytes + off;
317 		int i;
318 		for (i = 0; i < packbytes; i++, val >>= 8) {
319 			dst[i] = val & 0xff;
320 		}
321 		return true;
322 	}
323 	eprintf ("r_reg_set_value: Cannot set %s to 0x%" PFMT64x "\n", item->name, val);
324 	return false;
325 }
326