Skip to content

Commit af0a865

Browse files
committed
WIP - Totally remove host endianness dependence
- Adds endian aware functions - Removes references to host endian - Uses binary detected endianness else tries LE and restricts by RAsmPlugin - Fixes gdb debugger endianness when debugging BE qemu gdbserver Signed-off-by: Damien Zammit <[email protected]>
1 parent 1b29487 commit af0a865

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

127 files changed

+920
-729
lines changed

AUTHORS.md

+1
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ This release comes with contributions from the following people:
7474
- ampotos
7575
- capi_x
7676
- cosarara
77+
- damo22
7778
- dso (Adam Pridgen)
7879
- dunhame
7980
- dx

binr/rasm2/rasm2.c

+5-3
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,7 @@ int main (int argc, char *argv[]) {
332332
const char *env_bits = r_sys_getenv ("RASM2_BITS");
333333
unsigned char buf[R_ASM_BUFSIZE];
334334
char *arch = NULL, *file = NULL, *filters = NULL, *kernel = NULL, *cpu = NULL, *tmp;
335+
bool isbig = false;
335336
ut64 offset = 0;
336337
int fd = -1, dis = 0, ascii = 0, bin = 0, ret = 0, bits = 32, c, whatsop = 0;
337338
ut64 len = 0, idx = 0, skip = 0;
@@ -377,8 +378,8 @@ int main (int argc, char *argv[]) {
377378
r_asm_set_bits (a, sysbits);
378379
r_anal_set_bits (anal, sysbits);
379380
}
380-
r_asm_set_big_endian (a, false);
381-
r_anal_set_big_endian (anal, false);
381+
isbig = r_asm_set_big_endian (a, false);
382+
r_anal_set_big_endian (anal, isbig);
382383

383384
while ((c = getopt (argc, argv, "Ai:k:DCc:eEva:b:s:do:Bl:hjLf:F:wO:")) != -1) {
384385
switch (c) {
@@ -407,7 +408,8 @@ int main (int argc, char *argv[]) {
407408
dis = 2;
408409
break;
409410
case 'e':
410-
r_asm_set_big_endian (a, !a->big_endian);
411+
isbig = r_asm_set_big_endian (a, true);
412+
r_anal_set_big_endian (anal, isbig);
411413
break;
412414
case 'E':
413415
dis = 3;

binr/rax2/rax2.c

+2-5
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,14 @@ static int rax (char *str, int len, int last);
1515

1616
static int format_output (char mode, const char *s) {
1717
ut64 n = r_num_math (num, s);
18-
const char *str = (char*)&n;
1918
char strbits[65];
2019

2120
if (force_mode)
2221
mode = force_mode;
2322

2423
if (flags & 2) {
25-
/* swap endian */
26-
ut32 n2 = (n >> 32) ? 8 : 4;
27-
r_mem_copyendian ((ut8*)str, (ut8*)str, n2, 0);
24+
ut64 n2 = n;
25+
r_mem_swapendian ((ut8*)&n, (ut8*)&n2, (n >> 32) ? 8 : 4);
2826
}
2927
switch (mode) {
3028
case 'I': printf ("%"PFMT64d"\n", n); break;
@@ -307,7 +305,6 @@ static int rax (char *str, int len, int last) {
307305
} else if (flags & 2048) { // -t
308306
ut32 n = r_num_math (num, str);
309307
RPrint *p = r_print_new ();
310-
r_mem_copyendian ((ut8*) &n, (ut8*) &n, 4, !(flags & 2));
311308
r_print_date_unix (p, (const ut8*)&n, sizeof (ut32));
312309
r_print_free (p);
313310
return true;

doc/endian

+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
Endian issues
2+
=============
3+
4+
As hackers, we need to be aware of endianness.
5+
6+
Endianness can become a problem when you try to process buffers or streams
7+
of bytes and store intermediate values as integers with width larger than
8+
a single byte.
9+
10+
It can seem very easy to write the following code:
11+
12+
ut8 opcode[4] = {0x10, 0x20, 0x30, 0x40};
13+
ut32 value = *(ut32*)opcode;
14+
15+
... and then continue to use "value" in the code to represent the opcode.
16+
17+
This needs to be avoided!
18+
19+
Why? What is actually happening?
20+
21+
When you cast the opcode stream to a unsigned int, the compiler uses the endianness
22+
of the host to interpret the bytes and stores it in host endianness. This leads to
23+
very unportable code, because if you compile on a different endian machine, the
24+
value stored in "value" might be 0x40302010 instead of 0x10203040.
25+
26+
In the past, radare devs were not as strict about this issue, and as a result,
27+
needed to swap the endian of values regularly in the code.
28+
29+
Solution
30+
========
31+
32+
Use bitshifts and OR instructions to interpret bytes in a known endian.
33+
Instead of casting streams of bytes to larger width integers, do the following:
34+
35+
ut8 opcode[4] = {0x10, 0x20, 0x30, 0x40};
36+
ut32 value = opcode[0] | opcode[1] << 8 | opcode[2] << 16 | opcode[3] << 24;
37+
38+
or if you prefer the other endian:
39+
40+
ut32 value = opcode[3] | opcode[2] << 8 | opcode[1] << 16 | opcode[0] << 24;
41+
42+
This is much better because you actually know which endian your bytes are stored in
43+
within the integer value, REGARDLESS of the host endian of the machine.
44+
45+
46+
Endian helper functions
47+
=======================
48+
49+
Radare2 now uses helper functions to interpret all byte streams in a known endian.
50+
51+
Please use these at all times, eg:
52+
53+
val32 = r_read_be32(buffer) // reads 4 bytes from a stream in BE
54+
val32 = r_read_le32(buffer) // reads 4 bytes from a stream in LE
55+
val32 = r_read_ble32(buffer, isbig) // reads 4 bytes from a stream:
56+
// if isbig is true, reads in BE
57+
// otherwise reads in LE
58+
59+
There are a number of helper functions for 64, 32, 16, and 8 bit reads and writes.
60+
61+
(Note that 8 bit reads are equivalent to casting a single byte of the buffer
62+
to a ut8 value, ie endian is irrelevant).
63+
64+
Happy hacking!
65+
66+
- damo22
67+
68+

doc/fortunes.fun

+3
Original file line numberDiff line numberDiff line change
@@ -187,3 +187,6 @@ Run a command with unspecified long sequence of 'a', pancake will be summoned an
187187
In r2land usability is treated as a bug
188188
radare2 is WYSIWYF - what you see is what you fix
189189
Your endian swaps
190+
*(ut64*)buffer ought to be illegal
191+
MY ENDIAN IS HUUUGE
192+
enlarge your endian

doc/fortunes.nsfw

+1
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,4 @@ less stupid than putting CO2 in your ass.
2727
Puritans, ruining everything since the 16th century.
2828
Better fuck a watermelon.
2929
Can you deal with an ascii penis?
30+
two girls one endian

libr/anal/anal.c

-1
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,6 @@ R_API RAnal *r_anal_new() {
113113
anal->refs = r_anal_ref_list_new ();
114114
anal->types = r_anal_type_list_new ();
115115
r_anal_set_bits (anal, 32);
116-
r_anal_set_big_endian (anal, false);
117116
anal->plugins = r_list_newf ((RListFree) r_anal_plugin_free);
118117
if (anal->plugins) {
119118
for (i=0; anal_static_plugins[i]; i++) {

libr/anal/data.c

+7-7
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ static int is_string(const ut8 *buf, int size, int *len) {
3131
return 1;
3232
}
3333

34-
static int is_number(const ut8 *buf, int endian, int size) {
35-
ut64 n = r_mem_get_num (buf, size, endian);
34+
static int is_number(const ut8 *buf, int size) {
35+
ut64 n = r_mem_get_num (buf, size);
3636
return (n < UT32_MAX)? (int)n: 0;
3737
}
3838

@@ -48,12 +48,13 @@ static int is_invalid(const ut8 *buf, int size) {
4848
}
4949

5050
#define USE_IS_VALID_OFFSET 1
51-
static ut64 is_pointer(RIOBind *iob, const ut8 *buf, int endian, int size) {
51+
static ut64 is_pointer(RAnal *anal, const ut8 *buf, int size) {
5252
ut64 n;
5353
ut8 buf2[32];
54+
RIOBind *iob = &anal->iob;
5455
if (size > sizeof (buf2))
5556
size = sizeof (buf2);
56-
n = r_mem_get_num (buf, size, endian);
57+
n = r_mem_get_num (buf, size);
5758
if (!n) return 1; // null pointer
5859
#if USE_IS_VALID_OFFSET
5960
int r = iob->is_valid_offset (iob->io, n, 0);
@@ -227,7 +228,6 @@ R_API RAnalData *r_anal_data(RAnal *anal, ut64 addr, const ut8 *buf, int size) {
227228
ut64 dst = 0;
228229
int n, nsize = 0;
229230
int bits = anal->bits;
230-
int endi = !anal->big_endian;
231231
int word = R_MIN (8, bits / 8);
232232

233233
if (size < 4)
@@ -266,7 +266,7 @@ R_API RAnalData *r_anal_data(RAnal *anal, ut64 addr, const ut8 *buf, int size) {
266266
return r_anal_data_new (addr, R_ANAL_DATA_TYPE_HEADER, -1,
267267
buf, word);
268268
if (size >= word) {
269-
dst = is_pointer (&anal->iob, buf, endi, word);
269+
dst = is_pointer (anal, buf, word);
270270
if (dst) return r_anal_data_new (addr,
271271
R_ANAL_DATA_TYPE_POINTER, dst, buf, word);
272272
}
@@ -277,7 +277,7 @@ R_API RAnalData *r_anal_data(RAnal *anal, ut64 addr, const ut8 *buf, int size) {
277277
nsize, R_ANAL_DATA_TYPE_WIDE_STRING);
278278
}
279279
if (size >= word) {
280-
n = is_number (buf, endi, word);
280+
n = is_number (buf, word);
281281
if (n) return r_anal_data_new (addr, R_ANAL_DATA_TYPE_NUMBER,
282282
n, buf, word);
283283
}

libr/anal/esil.c

+25-26
Original file line numberDiff line numberDiff line change
@@ -1379,12 +1379,8 @@ static int esil_deceq(RAnalEsil *esil) {
13791379
static int esil_poke_n(RAnalEsil *esil, int bits) {
13801380
ut64 bitmask = genmask (bits - 1);
13811381
ut64 num, addr;
1382-
union {
1383-
ut8 byte;
1384-
ut16 word;
1385-
ut32 dword;
1386-
ut64 qword;
1387-
} n, n2;
1382+
ut8 b[sizeof(ut64)];
1383+
ut64 n;
13881384
char *dst = r_anal_esil_pop (esil);
13891385
char *src = r_anal_esil_pop (esil);
13901386
int bytes = bits / 8, ret = 0;
@@ -1398,16 +1394,15 @@ static int esil_poke_n(RAnalEsil *esil, int bits) {
13981394
if (dst && r_anal_esil_get_parm (esil, dst, &addr)) {
13991395
int type = r_anal_esil_get_parm_type (esil, src);
14001396
if (type != R_ANAL_ESIL_PARM_INTERNAL) {
1401-
n.qword = n2.qword = 0;
1402-
r_anal_esil_mem_read (esil, addr, (ut8 *)&n, bytes);
1403-
r_mem_copyendian ((ut8 *)&n2, (ut8 *)&n, bytes, !esil->anal->big_endian);
1404-
esil->old = n2.qword;
1397+
r_anal_esil_mem_read (esil, addr, b, bytes);
1398+
n = r_read_ble64 (b, esil->anal->big_endian);
1399+
esil->old = n;
14051400
esil->cur = (num & bitmask);
14061401
esil->lastsz = bits;
14071402
num = num & bitmask;
14081403
}
1409-
r_mem_copyendian ((ut8 *)&n, (ut8 *)&num, bytes, !esil->anal->big_endian);
1410-
ret = r_anal_esil_mem_write (esil, addr, (const ut8 *)&n, bytes);
1404+
r_write_ble64 (b, num, esil->anal->big_endian);
1405+
ret = r_anal_esil_mem_write (esil, addr, b, bytes);
14111406
}
14121407
}
14131408
free (src);
@@ -1433,30 +1428,31 @@ static int esil_poke(RAnalEsil *esil) {
14331428

14341429
static int esil_poke_some(RAnalEsil *esil) {
14351430
int i, ret = 0;
1431+
int regsize;
14361432
ut64 ptr, regs;
14371433
char *count, *dst = r_anal_esil_pop (esil);
1438-
if (dst) {
1434+
if (dst && r_anal_esil_get_parm_size (esil, dst, NULL, &regsize)) {
1435+
ut8 bytes = regsize / 8;
14391436
// reg
14401437
isregornum (esil, dst, &ptr);
14411438
count = r_anal_esil_pop (esil);
14421439
if (count) {
14431440
isregornum (esil, count, &regs);
14441441
if (regs > 0) {
1442+
ut8 b[bytes];
14451443
ut64 num64;
1446-
ut32 num32;
14471444
for (i = 0; i < regs; i++) {
14481445
char *foo = r_anal_esil_pop (esil);
14491446
isregornum (esil, foo, &num64);
14501447
/* TODO: implement peek here */
14511448
// read from $dst
1452-
num32 = num64;
1453-
ret = r_anal_esil_mem_write (esil, ptr,
1454-
(const ut8 *)&num32, sizeof (num32));
1455-
if (ret != sizeof (num32)) {
1449+
r_write_ble64 (b, num64, esil->anal->big_endian);
1450+
ret = r_anal_esil_mem_write (esil, ptr, b, bytes);
1451+
if (ret != bytes) {
14561452
//eprintf ("Cannot write at 0x%08" PFMT64x "\n", ptr);
14571453
esil->trap = 1;
14581454
}
1459-
ptr += 4;
1455+
ptr += bytes;
14601456
free (foo);
14611457
}
14621458
}
@@ -1481,9 +1477,11 @@ static int esil_peek_n(RAnalEsil *esil, int bits) {
14811477
return 0;
14821478
}
14831479
if (dst && isregornum (esil, dst, &addr)) {
1484-
ut64 a, b, bitmask = genmask (bits - 1);
1485-
ret = r_anal_esil_mem_read (esil, addr, (ut8 *)&a, bytes);
1486-
r_mem_copyendian ((ut8 *)&b, (const ut8 *)&a, bytes, !esil->anal->big_endian);
1480+
ut64 bitmask = genmask (bits - 1);
1481+
ut8 a[sizeof(ut64)];
1482+
ut64 b;
1483+
ret = r_anal_esil_mem_read (esil, addr, a, bytes);
1484+
b = r_read_ble64 (a, esil->anal->big_endian);
14871485
snprintf (res, sizeof (res), "0x%" PFMT64x, b & bitmask);
14881486
r_anal_esil_push (esil, res);
14891487
esil->lastsz = bits;
@@ -1521,20 +1519,21 @@ static int esil_peek_some(RAnalEsil *esil) {
15211519
isregornum (esil, count, &regs);
15221520
if (regs > 0) {
15231521
ut32 num32;
1522+
ut8 a[sizeof (ut32)];
15241523
for (i = 0; i < regs; i++) {
15251524
char *foo = r_anal_esil_pop (esil);
15261525
if (!foo) {
15271526
ERR ("Cannot pop in peek");
15281527
return 0;
15291528
}
1530-
ret = r_anal_esil_mem_read (esil, ptr,
1531-
(ut8 *)&num32, sizeof (num32));
1532-
if (ret == sizeof (num32)) {
1529+
ret = r_anal_esil_mem_read (esil, ptr, a, 4);
1530+
if (ret == sizeof (ut32)) {
1531+
num32 = r_read_ble32 (a, esil->anal->big_endian);
15331532
r_anal_esil_reg_write (esil, foo, num32);
15341533
} else {
15351534
eprintf ("Cannot peek from 0x%08" PFMT64x "\n", ptr);
15361535
}
1537-
ptr += 4;
1536+
ptr += sizeof (ut32);
15381537
free (foo);
15391538
}
15401539
}

libr/anal/fcn.c

+8-3
Original file line numberDiff line numberDiff line change
@@ -229,9 +229,14 @@ static int try_walkthrough_jmptbl(RAnal *anal, RAnalFunction *fcn, int depth, ut
229229
ut64 offs, sz = anal->bits >> 3;
230230
if (!jmptbl) return 0;
231231
anal->iob.read_at (anal->iob.io, ptr, jmptbl, MAX_JMPTBL_SIZE);
232-
for (offs = 0; offs < MAX_JMPTBL_SIZE; offs += sz) {
233-
ut64 jmpptr = 0;
234-
r_mem_copyendian ((ut8*)&jmpptr, jmptbl + offs, sz, !anal->big_endian);
232+
for (offs = 0; offs + sz - 1 < MAX_JMPTBL_SIZE; offs += sz) {
233+
ut64 jmpptr;
234+
switch (sz) {
235+
case 1: jmpptr = r_read_le8 (jmptbl + offs); break;
236+
case 2: jmpptr = r_read_le16 (jmptbl + offs); break;
237+
case 4: jmpptr = r_read_le32 (jmptbl + offs); break;
238+
default: jmpptr = r_read_le64 (jmptbl + offs); break;
239+
}
235240
if (anal->limit) {
236241
if (jmpptr < anal->limit->from || jmpptr > anal->limit->to)
237242
break;

libr/anal/p/anal_h8300.c

+2-3
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ static void h8300_anal_jmp(RAnalOp *op, ut64 addr, const ut8 *buf) {
5353
break;
5454
case H8300_JMP_2:
5555
op->type = R_ANAL_OP_TYPE_JMP;
56-
r_mem_copyendian((ut8*)&ad, buf + 2, sizeof(ut16), !LIL_ENDIAN);
56+
r_mem_swapendian ((ut8*)&ad, buf + 2, sizeof (ut16));
5757
op->jump = ad;
5858
break;
5959
case H8300_JMP_3:
@@ -72,8 +72,7 @@ static void h8300_anal_jsr(RAnalOp *op, ut64 addr, const ut8 *buf) {
7272
break;
7373
case H8300_JSR_2:
7474
op->type = R_ANAL_OP_TYPE_CALL;
75-
r_mem_copyendian((ut8*)&ad, buf + 2,
76-
sizeof(ut16), !LIL_ENDIAN);
75+
r_mem_swapendian ((ut8*)&ad, buf + 2, sizeof (ut16));
7776
op->jump = ad;
7877
op->fail = addr + 4;
7978
break;

libr/anal/p/anal_mips_gnu.c

+3-6
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,8 @@ static const char* mips_reg_decode(unsigned reg_num) {
1919
return NULL;
2020
}
2121

22-
static int mips_op(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *b_in, int len) {
22+
static int mips_op(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *b, int len) {
2323
unsigned int opcode;
24-
ut8 b[4];
2524
// WIP char buf[10]; int reg; int family;
2625
int optype, oplen = (anal->bits==16)?2:4;
2726

@@ -35,10 +34,8 @@ static int mips_op(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *b_in, int len
3534
op->addr = addr;
3635
r_strbuf_init (&op->esil);
3736

38-
// Reminder: r_mem_copyendian swaps if arg `endian` ==0 ...
39-
// When anal->big_endian is "false", as for mipsel architecture, we NEED to swap here for the below analysis to work.
40-
r_mem_copyendian ((ut8*)&opcode, b_in, 4, anal->big_endian ? 1 : 0);
41-
r_mem_copyendian (b, b_in, 4, anal->big_endian ? 1 : 0);
37+
// Be endian aware
38+
opcode = r_read_ble32 (b, anal->big_endian);
4239

4340
// eprintf ("MIPS: %02x %02x %02x %02x (after endian: big=%d)\n", b[0], b[1], b[2], b[3], anal->big_endian);
4441
if (opcode == 0) {

libr/anal/p/anal_ppc_gnu.c

+1-4
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,8 @@
77

88
// NOTE: buf should be at least 16 bytes!
99
// XXX addr should be off_t for 64 love
10-
static int ppc_op(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *_bytes, int len) {
10+
static int ppc_op(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *bytes, int len) {
1111
//int arch_ppc_op(ut64 addr, const u8 *bytes, struct op_t *op)
12-
// TODO swap endian here??
13-
char bytes[1024];
14-
r_mem_copyendian ((ut8*)bytes, _bytes, 4, 1);
1512
// XXX hack
1613
int opcode = (bytes[0] & 0xf8) >> 3; // bytes 0-5
1714
short baddr = ((bytes[2]<<8) | (bytes[3]&0xfc));// 16-29

0 commit comments

Comments
 (0)