2016-11-15 16:20:10 +01:00
|
|
|
/* radare - LGPL - Copyright 2009-2016 - pancake */
|
2009-09-18 20:11:42 +02:00
|
|
|
|
|
|
|
#include <r_reg.h>
|
2009-09-19 21:54:22 +02:00
|
|
|
#include <r_util.h>
|
2009-09-18 20:11:42 +02:00
|
|
|
|
2016-11-14 23:58:29 +01:00
|
|
|
R_API ut64 r_reg_get_value_big(RReg *reg, RRegItem *item, utX *val) {
|
|
|
|
RRegSet *regset;
|
|
|
|
int off;
|
|
|
|
ut64 ret = 0LL;
|
2016-11-15 01:12:37 +01:00
|
|
|
if (!reg || !item) {
|
2016-11-14 23:58:29 +01:00
|
|
|
return 0LL;
|
2016-11-15 01:12:37 +01:00
|
|
|
}
|
2016-11-14 23:58:29 +01:00
|
|
|
off = BITS2BYTES (item->offset);
|
|
|
|
regset = ®->regset[item->arena];
|
|
|
|
switch (item->size) {
|
|
|
|
case 80: // word + qword
|
|
|
|
if (regset->arena->bytes && (off + 10 <= regset->arena->size)) {
|
|
|
|
val->v80.Low = *((ut64 *)(regset->arena->bytes+off));
|
|
|
|
val->v80.High =*((ut16 *)(regset->arena->bytes+off+8));
|
2016-11-15 01:12:37 +01:00
|
|
|
} else {
|
|
|
|
eprintf ("r_reg_get_value: null or oob arena for current regset\n");
|
|
|
|
}
|
2016-11-14 23:58:29 +01:00
|
|
|
ret = val->v80.Low;
|
|
|
|
break;
|
|
|
|
case 96: // dword + qword
|
|
|
|
if (regset->arena->bytes && (off + 12 <= regset->arena->size)) {
|
|
|
|
val->v96.Low = *((ut64 *)(regset->arena->bytes+off));
|
|
|
|
val->v96.High =*((ut32 *)(regset->arena->bytes+off+8));
|
2016-11-15 01:12:37 +01:00
|
|
|
} else {
|
|
|
|
eprintf ("r_reg_get_value: null or oob arena for current regset\n");
|
|
|
|
}
|
2016-11-14 23:58:29 +01:00
|
|
|
ret = val->v96.Low;
|
|
|
|
break;
|
|
|
|
case 128:// qword + qword
|
|
|
|
if (regset->arena->bytes && (off + 16 <= regset->arena->size)) {
|
|
|
|
val->v128.Low = *((ut64 *)(regset->arena->bytes+off));
|
|
|
|
val->v128.High =*((ut64 *)(regset->arena->bytes+off+8));
|
2016-11-15 01:12:37 +01:00
|
|
|
} else {
|
|
|
|
eprintf ("r_reg_get_value: null or oob arena for current regset\n");
|
|
|
|
}
|
2016-11-14 23:58:29 +01:00
|
|
|
ret = val->v128.Low;
|
|
|
|
break;
|
|
|
|
//case 256:// qword + qword + qword + qword
|
|
|
|
// break;
|
|
|
|
default:
|
|
|
|
eprintf ("r_reg_get_value_big: Bit size %d not supported\n", item->size);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
2010-09-23 20:42:35 +02:00
|
|
|
R_API ut64 r_reg_get_value(RReg *reg, RRegItem *item) {
|
2014-01-08 23:23:06 +01:00
|
|
|
RRegSet *regset;
|
2010-10-14 19:01:14 +02:00
|
|
|
int off;
|
2009-09-18 20:11:42 +02:00
|
|
|
ut64 ret = 0LL;
|
2016-11-15 01:12:37 +01:00
|
|
|
if (!reg || !item) {
|
2010-10-14 19:01:14 +02:00
|
|
|
return 0LL;
|
2016-11-15 01:12:37 +01:00
|
|
|
}
|
2010-10-14 19:01:14 +02:00
|
|
|
off = BITS2BYTES (item->offset);
|
2016-11-14 23:58:29 +01:00
|
|
|
regset = ®->regset[item->arena];
|
2010-03-01 10:49:04 +01:00
|
|
|
switch (item->size) {
|
2010-09-24 16:45:56 +02:00
|
|
|
case 1:
|
2016-11-15 01:12:37 +01:00
|
|
|
{
|
|
|
|
int offset = item->offset / 8;
|
2016-11-15 14:40:16 +01:00
|
|
|
if (offset + item->size >= regset->arena->size) {
|
2016-11-15 01:12:37 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
ret = (regset->arena->bytes[offset] &
|
|
|
|
(1 << (item->offset % 8))) ? 1 : 0;
|
|
|
|
}
|
2010-09-24 16:45:56 +02:00
|
|
|
break;
|
2016-01-11 03:08:24 +01:00
|
|
|
case 4:
|
|
|
|
if (regset->arena->size - off - 1 >= 0) {
|
2016-04-26 19:09:15 +10:00
|
|
|
ret = (r_read_at_ble8 (regset->arena->bytes, off)) & 0xF;
|
2016-01-11 03:08:24 +01:00
|
|
|
}
|
|
|
|
break;
|
2010-03-01 10:49:04 +01:00
|
|
|
case 8:
|
2015-12-08 23:55:23 +01:00
|
|
|
if (regset->arena->size - off - 1 >= 0) {
|
2016-04-26 19:09:15 +10:00
|
|
|
ret = r_read_at_ble8 (regset->arena->bytes, off);
|
2014-01-11 23:48:55 +01:00
|
|
|
}
|
2010-03-01 10:49:04 +01:00
|
|
|
break;
|
|
|
|
case 16:
|
2015-12-08 23:55:23 +01:00
|
|
|
if (regset->arena->size - off - 2 >= 0) {
|
2016-04-26 19:09:15 +10:00
|
|
|
ret = r_read_ble16 (regset->arena->bytes + off, reg->big_endian);
|
2014-01-11 23:48:55 +01:00
|
|
|
}
|
2010-03-01 10:49:04 +01:00
|
|
|
break;
|
|
|
|
case 32:
|
2015-12-08 23:55:23 +01:00
|
|
|
if (off + 4 <= regset->arena->size) {
|
2016-04-26 19:09:15 +10:00
|
|
|
ret = r_read_ble32 (regset->arena->bytes + off, reg->big_endian);
|
2016-11-15 01:12:37 +01:00
|
|
|
} else {
|
|
|
|
eprintf ("r_reg_get_value: 32bit oob read %d\n", off);
|
|
|
|
}
|
2010-03-01 10:49:04 +01:00
|
|
|
break;
|
|
|
|
case 64:
|
2016-04-26 19:09:15 +10:00
|
|
|
if (regset->arena->bytes && (off + 8 <= regset->arena->size)) {
|
|
|
|
ret = r_read_ble64 (regset->arena->bytes + off, reg->big_endian);
|
2016-11-15 01:12:37 +01:00
|
|
|
} else {
|
|
|
|
eprintf ("r_reg_get_value: null or oob arena for current regset\n");
|
|
|
|
}
|
2010-03-01 10:49:04 +01:00
|
|
|
break;
|
2015-10-22 13:38:30 +02:00
|
|
|
case 80: // long double
|
|
|
|
case 96: // long floating value
|
2015-10-22 15:07:32 +03:00
|
|
|
// FIXME: It is a precision loss, please implement me properly!
|
2015-10-22 13:38:30 +02:00
|
|
|
ret = (ut64)r_reg_get_longdouble (reg, item);
|
|
|
|
break;
|
2010-03-01 10:49:04 +01:00
|
|
|
default:
|
|
|
|
eprintf ("r_reg_get_value: Bit size %d not supported\n", item->size);
|
|
|
|
break;
|
2009-09-18 20:11:42 +02:00
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2015-09-21 23:40:17 +02:00
|
|
|
R_API bool r_reg_set_value(RReg *reg, RRegItem *item, ut64 value) {
|
2015-08-25 12:40:21 +02:00
|
|
|
int fits_in_arena;
|
2016-04-26 19:09:15 +10:00
|
|
|
ut8 bytes[12];
|
|
|
|
ut8 *src = bytes;
|
2010-02-03 14:34:00 +01:00
|
|
|
|
2014-03-21 03:18:10 +01:00
|
|
|
if (!item) {
|
|
|
|
eprintf ("r_reg_set_value: item is NULL\n");
|
2015-09-14 02:08:31 +02:00
|
|
|
return false;
|
2014-03-21 03:18:10 +01:00
|
|
|
}
|
2010-02-03 14:34:00 +01:00
|
|
|
switch (item->size) {
|
2015-08-23 04:43:31 +02:00
|
|
|
case 80:
|
2015-10-22 13:38:30 +02:00
|
|
|
case 96: // long floating value
|
2015-12-08 23:55:23 +01:00
|
|
|
r_reg_set_longdouble (reg, item, (long double)value);
|
2015-08-23 04:43:31 +02:00
|
|
|
break;
|
2015-08-25 12:40:21 +02:00
|
|
|
case 64:
|
2016-11-15 14:40:16 +01:00
|
|
|
if (reg->big_endian) {
|
|
|
|
r_write_be64 (src, value);
|
|
|
|
} else {
|
|
|
|
r_write_le64 (src, value);
|
|
|
|
}
|
2015-08-25 12:40:21 +02:00
|
|
|
break;
|
|
|
|
case 32:
|
2016-11-15 14:40:16 +01:00
|
|
|
if (reg->big_endian) {
|
|
|
|
r_write_be32 (src, value);
|
|
|
|
} else {
|
|
|
|
r_write_le32 (src, value);
|
|
|
|
}
|
2015-08-25 12:40:21 +02:00
|
|
|
break;
|
|
|
|
case 16:
|
2016-11-15 14:40:16 +01:00
|
|
|
if (reg->big_endian) {
|
|
|
|
r_write_be16 (src, value);
|
|
|
|
} else {
|
|
|
|
r_write_le16 (src, value);
|
|
|
|
}
|
2015-08-25 12:40:21 +02:00
|
|
|
break;
|
|
|
|
case 8:
|
2016-11-15 14:40:16 +01:00
|
|
|
r_write_ble8 (src, (ut8)(value & UT8_MAX));
|
2015-08-25 12:40:21 +02:00
|
|
|
break;
|
2014-01-08 23:23:06 +01:00
|
|
|
case 1:
|
2010-02-03 14:34:00 +01:00
|
|
|
if (value) {
|
2016-11-14 23:58:29 +01:00
|
|
|
ut8 *buf = reg->regset[item->arena].arena->bytes + (item->offset / 8);
|
2015-12-08 23:55:23 +01:00
|
|
|
int bit = (item->offset % 8);
|
|
|
|
ut8 mask = (1 << bit);
|
|
|
|
buf[0] = (buf[0] & (0xff ^ mask)) | mask;
|
2010-02-03 14:34:00 +01:00
|
|
|
} else {
|
2016-11-15 14:40:16 +01:00
|
|
|
int idx = item->offset / 8;
|
|
|
|
RRegArena *arena = reg->regset[item->arena].arena;
|
2016-11-16 20:48:48 +01:00
|
|
|
if (idx + item->size > arena->size) {
|
2016-11-15 14:40:16 +01:00
|
|
|
eprintf ("RRegSetOverflow %d vs %d\n", idx + item->size, arena->size);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
ut8 *buf = arena->bytes + idx;
|
2015-08-23 03:58:49 +02:00
|
|
|
int bit = item->offset % 8;
|
|
|
|
ut8 mask = 0xff ^ (1 << bit);
|
2010-02-03 14:34:00 +01:00
|
|
|
buf[0] = (buf[0] & mask) | 0;
|
2009-09-19 21:54:22 +02:00
|
|
|
}
|
2015-09-14 02:08:31 +02:00
|
|
|
return true;
|
2014-04-26 01:44:57 +04:00
|
|
|
default:
|
2010-03-01 10:49:04 +01:00
|
|
|
eprintf ("r_reg_set_value: Bit size %d not supported\n", item->size);
|
2015-09-14 02:08:31 +02:00
|
|
|
return false;
|
2009-09-18 20:11:42 +02:00
|
|
|
}
|
2016-11-14 23:58:29 +01:00
|
|
|
fits_in_arena = (reg->regset[item->arena].arena->size - BITS2BYTES (item->offset) - BITS2BYTES (item->size)) >= 0;
|
2015-08-25 12:40:21 +02:00
|
|
|
if (src && fits_in_arena) {
|
2016-11-14 23:58:29 +01:00
|
|
|
r_mem_copybits (reg->regset[item->arena].arena->bytes +
|
2015-12-08 23:55:23 +01:00
|
|
|
BITS2BYTES (item->offset),
|
|
|
|
src, item->size);
|
2015-09-14 02:08:31 +02:00
|
|
|
return true;
|
2014-01-11 23:48:55 +01:00
|
|
|
}
|
2015-12-08 23:55:23 +01:00
|
|
|
eprintf ("r_reg_set_value: Cannot set %s to 0x%" PFMT64x "\n", item->name, value);
|
2015-09-14 02:08:31 +02:00
|
|
|
return false;
|
2009-09-18 20:11:42 +02:00
|
|
|
}
|
|
|
|
|
2014-11-18 17:21:42 +01:00
|
|
|
R_API ut64 r_reg_set_bvalue(RReg *reg, RRegItem *item, const char *str) {
|
2015-08-23 03:58:49 +02:00
|
|
|
ut64 num = UT64_MAX;
|
|
|
|
if (item && item->flags && str) {
|
|
|
|
num = r_str_bits_from_string (str, item->flags);
|
2016-11-20 11:30:15 +01:00
|
|
|
if (num == UT64_MAX) {
|
2015-08-23 03:58:49 +02:00
|
|
|
num = r_num_math (NULL, str);
|
2016-11-20 11:30:15 +01:00
|
|
|
}
|
2015-08-23 03:58:49 +02:00
|
|
|
r_reg_set_value (reg, item, num);
|
|
|
|
}
|
2014-11-18 17:21:42 +01:00
|
|
|
return num;
|
|
|
|
}
|
|
|
|
|
2015-08-23 04:43:31 +02:00
|
|
|
R_API R_HEAP char *r_reg_get_bvalue(RReg *reg, RRegItem *item) {
|
2015-08-23 03:58:49 +02:00
|
|
|
char *out = NULL;
|
|
|
|
if (reg && item && item->flags) {
|
2015-12-08 23:55:23 +01:00
|
|
|
out = malloc (strlen (item->flags) + 1);
|
2015-08-23 03:58:49 +02:00
|
|
|
if (out) {
|
|
|
|
ut64 num = r_reg_get_value (reg, item);
|
2015-12-08 23:55:23 +01:00
|
|
|
r_str_bits (out, (ut8 *)&num,
|
2015-08-23 03:58:49 +02:00
|
|
|
strlen (item->flags) * 8, item->flags);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return out;
|
2009-09-18 20:11:42 +02:00
|
|
|
}
|
|
|
|
|
2015-08-23 03:58:49 +02:00
|
|
|
/* packed registers */
|
|
|
|
// packbits can be 8, 16, 32 or 64
|
|
|
|
// result value is always casted into ut64
|
2015-10-29 20:02:13 +01:00
|
|
|
// TODO: use item->packed_size
|
2015-08-23 03:58:49 +02:00
|
|
|
R_API ut64 r_reg_get_pack(RReg *reg, RRegItem *item, int packidx, int packbits) {
|
2015-08-23 04:08:01 +02:00
|
|
|
int packbytes, packmod;
|
2015-08-23 03:58:49 +02:00
|
|
|
ut64 ret = 0LL;
|
|
|
|
RRegSet *regset;
|
|
|
|
int off;
|
2016-11-20 11:30:15 +01:00
|
|
|
if (!reg || !item) {
|
2015-08-23 03:58:49 +02:00
|
|
|
return 0LL;
|
2016-11-20 11:30:15 +01:00
|
|
|
}
|
2015-12-08 23:55:23 +01:00
|
|
|
if (packbits < 1) {
|
2015-08-23 04:08:01 +02:00
|
|
|
packbits = item->packed_size;
|
|
|
|
}
|
|
|
|
packbytes = packbits / 8;
|
|
|
|
packmod = packbits % 8;
|
2015-08-23 03:58:49 +02:00
|
|
|
if (packmod) {
|
|
|
|
eprintf ("Invalid bit size for packet register\n");
|
|
|
|
return 0LL;
|
|
|
|
}
|
|
|
|
off = BITS2BYTES (item->offset);
|
2016-11-14 23:58:29 +01:00
|
|
|
regset = ®->regset[item->arena];
|
2015-08-23 03:58:49 +02:00
|
|
|
off += (packidx * packbytes);
|
|
|
|
if (regset->arena->size - off - 1 >= 0) {
|
|
|
|
memcpy (&ret, regset->arena->bytes + off, packbytes);
|
|
|
|
}
|
2009-09-18 20:11:42 +02:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2015-08-23 03:58:49 +02:00
|
|
|
R_API int r_reg_set_pack(RReg *reg, RRegItem *item, int packidx, int packbits, ut64 val) {
|
2015-08-24 01:58:06 +02:00
|
|
|
int off, packbytes, packmod;
|
2009-09-18 20:11:42 +02:00
|
|
|
|
2015-08-23 03:58:49 +02:00
|
|
|
if (!reg || !item) {
|
|
|
|
eprintf ("r_reg_set_value: item is NULL\n");
|
2015-09-14 02:08:31 +02:00
|
|
|
return false;
|
2015-08-23 03:58:49 +02:00
|
|
|
}
|
2015-12-08 23:55:23 +01:00
|
|
|
if (packbits < 1) {
|
2015-08-23 04:08:01 +02:00
|
|
|
packbits = item->packed_size;
|
|
|
|
}
|
2015-08-24 01:58:06 +02:00
|
|
|
off = item->offset;
|
2015-08-23 04:08:01 +02:00
|
|
|
packbytes = packbits / 8;
|
|
|
|
packmod = packbits % 8;
|
|
|
|
if (packidx * packbits > item->size) {
|
|
|
|
eprintf ("Packed index is beyond the register size\n");
|
2015-09-14 02:08:31 +02:00
|
|
|
return false;
|
2015-08-23 04:08:01 +02:00
|
|
|
}
|
2015-08-23 03:58:49 +02:00
|
|
|
if (packmod) {
|
|
|
|
eprintf ("Invalid bit size for packet register\n");
|
2015-09-14 02:08:31 +02:00
|
|
|
return false;
|
2015-08-23 03:58:49 +02:00
|
|
|
}
|
2016-11-14 23:58:29 +01:00
|
|
|
if (reg->regset[item->arena].arena->size - BITS2BYTES (off) - BITS2BYTES (packbytes) >= 0) {
|
|
|
|
ut8 *dst = reg->regset[item->arena].arena->bytes + BITS2BYTES (off);
|
2015-12-08 23:55:23 +01:00
|
|
|
r_mem_copybits (dst, (ut8 *)&val, packbytes);
|
2015-09-14 02:08:31 +02:00
|
|
|
return true;
|
2015-08-23 03:58:49 +02:00
|
|
|
}
|
2015-12-08 23:55:23 +01:00
|
|
|
eprintf ("r_reg_set_value: Cannot set %s to 0x%" PFMT64x "\n", item->name, val);
|
2015-09-14 02:08:31 +02:00
|
|
|
return false;
|
2009-09-18 20:11:42 +02:00
|
|
|
}
|