From 304445ae3f7a159be55fa91b95428251ef8a362e Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Wed, 24 Jan 2018 18:50:40 +0100
Subject: Improved the support of some unusual endiannesses.

---
 ChangeLog                         |  12 +++
 plugins/pychrysalide/arch/vmpa.c  |   3 +-
 src/common/endianness.c           | 212 +++++++++++++++++++++++---------------
 src/common/endianness.h           |   4 +-
 tests/analysis/contents/endian.py | 129 +++++++++++++++++++++++
 5 files changed, 274 insertions(+), 86 deletions(-)
 create mode 100644 tests/analysis/contents/endian.py

diff --git a/ChangeLog b/ChangeLog
index d80a44d..ced1ad5 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,17 @@
 18-01-24  Cyrille Bagard <nocbos@gmail.com>
 
+	* plugins/pychrysalide/arch/vmpa.c:
+	Update code.
+
+	* src/common/endianness.c:
+	* src/common/endianness.h:
+	Improve the support of some unusual endiannesses.
+
+	* tests/analysis/contents/endian.py:
+	New entry: extend the test suite with some extra cases.
+
+18-01-24  Cyrille Bagard <nocbos@gmail.com>
+
 	* src/analysis/binary.c:
 	Clean the content of loaded binaries.
 
diff --git a/plugins/pychrysalide/arch/vmpa.c b/plugins/pychrysalide/arch/vmpa.c
index 413d67b..41fb1ad 100644
--- a/plugins/pychrysalide/arch/vmpa.c
+++ b/plugins/pychrysalide/arch/vmpa.c
@@ -554,7 +554,8 @@ static bool py_vmpa_define_constants(PyTypeObject *obj_type)
 
     /* TODO : à bouger vers base ? */
     result &= PyDict_AddIntMacro(obj_type, SRE_LITTLE);
-    result &= PyDict_AddIntMacro(obj_type, SRE_MIDDLE);
+    result &= PyDict_AddIntMacro(obj_type, SRE_LITTLE_WORD);
+    result &= PyDict_AddIntMacro(obj_type, SRE_BIG_WORD);
     result &= PyDict_AddIntMacro(obj_type, SRE_BIG);
 
     return result;
diff --git a/src/common/endianness.c b/src/common/endianness.c
index 4dcee22..3aeca00 100755
--- a/src/common/endianness.c
+++ b/src/common/endianness.c
@@ -24,11 +24,25 @@
 #include "endianness.h"
 
 
+#include <assert.h>
 #include <stdarg.h>
 #include <string.h>
 
 
 
+/**
+ * Mutualisation des aiguillages...
+ */
+
+#if __BYTE_ORDER != __LITTLE_ENDIAN && __BYTE_ORDER != __BIG_ENDIAN
+
+    /* __PDP_ENDIAN et Cie... */
+#   error "Congratulations! Your byte order is not supported!"
+
+#endif
+
+
+
 /* ---------------------------------------------------------------------------------- */
 /*                             CONVERSION ENTRE BOUTISMES                             */
 /* ---------------------------------------------------------------------------------- */
@@ -63,18 +77,10 @@ uint16_t swap_u16(const uint16_t *value, SourceEndian endian)
 
             result = ((*value >> 0) & 0xff) << 8 | ((*value >> 8) & 0xff) << 0;
 
-#else
-
-#   error "TODO : PDP !"
-
 #endif
 
             break;
 
-        case SRE_MIDDLE:
-            /* TODO */
-            break;
-
         case SRE_BIG:
 
 #if __BYTE_ORDER == __LITTLE_ENDIAN
@@ -85,14 +91,13 @@ uint16_t swap_u16(const uint16_t *value, SourceEndian endian)
 
             result = *value;
 
-#else
-
-#   error "TODO : PDP !"
-
 #endif
 
             break;
 
+        default:
+            assert(false);
+            break;
 
     }
 
@@ -131,18 +136,10 @@ uint32_t swap_u32(const uint32_t *value, SourceEndian endian)
             result = ((*value >>  0) & 0xff) << 24 | ((*value >>  8) & 0xff) << 16
                    | ((*value >> 16) & 0xff) << 8  | ((*value >> 24) & 0xff) << 0;
 
-#else
-
-#   error "TODO : PDP !"
-
 #endif
 
             break;
 
-        case SRE_MIDDLE:
-            /* TODO */
-            break;
-
         case SRE_BIG:
 
 #if __BYTE_ORDER == __LITTLE_ENDIAN
@@ -154,14 +151,13 @@ uint32_t swap_u32(const uint32_t *value, SourceEndian endian)
 
             result = *value;
 
-#else
-
-#   error "TODO : PDP !"
-
 #endif
 
             break;
 
+        default:
+            assert(false);
+            break;
 
     }
 
@@ -202,18 +198,10 @@ uint64_t swap_u64(const uint64_t *value, SourceEndian endian)
                    | ((*value >> 32) & 0xff) << 24 | ((*value >> 40) & 0xff) << 16
                    | ((*value >> 48) & 0xff) << 8  | ((*value >> 56) & 0xff) << 0;
 
-#else
-
-#   error "TODO : PDP !"
-
 #endif
 
             break;
 
-        case SRE_MIDDLE:
-            /* TODO */
-            break;
-
         case SRE_BIG:
 
 #if __BYTE_ORDER == __LITTLE_ENDIAN
@@ -227,14 +215,13 @@ uint64_t swap_u64(const uint64_t *value, SourceEndian endian)
 
             result = *value;
 
-#else
-
-#   error "TODO : PDP !"
-
 #endif
 
             break;
 
+        default:
+            assert(false);
+            break;
 
     }
 
@@ -349,16 +336,36 @@ bool read_u16(uint16_t *target, const bin_t *data, phys_t *pos, phys_t end, Sour
 
             *target = data[*pos + 1] | (uint16_t)data[*pos] << 8;
 
-#else
+#endif
+
+            break;
+
+        case SRE_LITTLE_WORD:
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
 
-#   error "TODO : PDP !"
+            *target = data[*pos] << 8 | (uint16_t)data[*pos + 1];
+
+#elif __BYTE_ORDER == __BIG_ENDIAN
+
+            *target = data[*pos + 1] << 8 | (uint16_t)data[*pos];
 
 #endif
 
             break;
 
-        case SRE_MIDDLE:
-            /* TODO */
+        case SRE_BIG_WORD:
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+
+            *target = data[*pos + 1] << 8 | (uint16_t)data[*pos];
+
+#elif __BYTE_ORDER == __BIG_ENDIAN
+
+            *target = data[*pos] << 8 | (uint16_t)data[*pos + 1];
+
+#endif
+
             break;
 
         case SRE_BIG:
@@ -371,14 +378,13 @@ bool read_u16(uint16_t *target, const bin_t *data, phys_t *pos, phys_t end, Sour
 
             *target = data[*pos] | (uint16_t)data[*pos + 1] << 8;
 
-#else
-
-#   error "TODO : PDP !"
-
 #endif
 
             break;
 
+        default:
+            return false;
+            break;
 
     }
 
@@ -424,16 +430,40 @@ bool read_u32(uint32_t *target, const bin_t *data, phys_t *pos, phys_t end, Sour
             *target = data[*pos + 3] | (uint32_t)data[*pos + 2] << 8;
             *target |= data[*pos + 1] << 16 | (uint32_t)data[*pos] << 24;
 
-#else
+#endif
+
+            break;
+
+        case SRE_LITTLE_WORD:
 
-#   error "TODO : PDP !"
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+
+            *target = data[*pos] << 8 | (uint32_t)data[*pos + 1];
+            *target |= data[*pos + 2] << 24 | (uint32_t)data[*pos + 3] << 16;
+
+#elif __BYTE_ORDER == __BIG_ENDIAN
+
+            *target = data[*pos + 3] << 8 | (uint32_t)data[*pos + 2];
+            *target |= data[*pos + 1] << 24 | (uint32_t)data[*pos] << 16;
 
 #endif
 
             break;
 
-        case SRE_MIDDLE:
-            /* TODO */
+        case SRE_BIG_WORD:
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+
+            *target = data[*pos + 3] << 8 | (uint32_t)data[*pos + 2];
+            *target |= data[*pos + 1] << 24 | (uint32_t)data[*pos] << 16;
+
+#elif __BYTE_ORDER == __BIG_ENDIAN
+
+            *target = data[*pos] << 8 | (uint32_t)data[*pos + 1];
+            *target |= data[*pos + 2] << 24 | (uint32_t)data[*pos + 3] << 16;
+
+#endif
+
             break;
 
         case SRE_BIG:
@@ -448,14 +478,13 @@ bool read_u32(uint32_t *target, const bin_t *data, phys_t *pos, phys_t end, Sour
             *target = data[*pos] | (uint32_t)data[*pos + 1] << 8;
             *target |= data[*pos + 2] << 16 | (uint32_t)data[*pos + 3] << 24;
 
-#else
-
-#   error "TODO : PDP !"
-
 #endif
 
             break;
 
+    default:
+        return false;
+        break;
 
     }
 
@@ -505,16 +534,48 @@ bool read_u64(uint64_t *target, const bin_t *data, phys_t *pos, phys_t end, Sour
             *target |= (uint64_t)data[*pos + 3] << 32 | (uint64_t)data[*pos + 2] << 40;
             *target |= (uint64_t)data[*pos + 1] << 48 | (uint64_t)data[*pos] << 56;
 
-#else
+#endif
+
+            break;
+
+        case SRE_LITTLE_WORD:
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
 
-#   error "TODO : PDP !"
+            *target = (uint64_t)data[*pos] << 8 | (uint64_t)data[*pos + 1];
+            *target |= (uint64_t)data[*pos + 2] << 24 | (uint64_t)data[*pos + 3] << 16;
+            *target |= (uint64_t)data[*pos + 4] << 40 | (uint64_t)data[*pos + 5] << 32;
+            *target |= (uint64_t)data[*pos + 6] << 56 | (uint64_t)data[*pos + 7] << 48;
+
+#elif __BYTE_ORDER == __BIG_ENDIAN
+
+            *target = (uint64_t)data[*pos + 7] << 8 | (uint64_t)data[*pos + 6];
+            *target |= (uint64_t)data[*pos + 5] << 24 | (uint64_t)data[*pos + 4] << 16;
+            *target |= (uint64_t)data[*pos + 3] << 40 | (uint64_t)data[*pos + 2] << 32;
+            *target |= (uint64_t)data[*pos + 1] << 56 | (uint64_t)data[*pos] << 48;
 
 #endif
 
             break;
 
-        case SRE_MIDDLE:
-            /* TODO */
+        case SRE_BIG_WORD:
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+
+            *target = (uint64_t)data[*pos + 7] << 8 | (uint64_t)data[*pos + 6];
+            *target |= (uint64_t)data[*pos + 5] << 24 | (uint64_t)data[*pos + 4] << 16;
+            *target |= (uint64_t)data[*pos + 3] << 40 | (uint64_t)data[*pos + 2] << 32;
+            *target |= (uint64_t)data[*pos + 1] << 56 | (uint64_t)data[*pos] << 48;
+
+#elif __BYTE_ORDER == __BIG_ENDIAN
+
+            *target = (uint64_t)data[*pos] << 8| (uint64_t)data[*pos + 1];
+            *target |= (uint64_t)data[*pos + 2] << 24 | (uint64_t)data[*pos + 3] << 16;
+            *target |= (uint64_t)data[*pos + 4] << 40 | (uint64_t)data[*pos + 5] << 32;
+            *target |= (uint64_t)data[*pos + 6] << 56 | (uint64_t)data[*pos + 7] << 48;
+
+#endif
+
             break;
 
         case SRE_BIG:
@@ -533,14 +594,13 @@ bool read_u64(uint64_t *target, const bin_t *data, phys_t *pos, phys_t end, Sour
             *target |= (uint64_t)data[*pos + 4] << 32 | (uint64_t)data[*pos + 5] << 40;
             *target |= (uint64_t)data[*pos + 6] << 48 | (uint64_t)data[*pos + 7] << 56;
 
-#else
-
-#   error "TODO : PDP !"
-
 #endif
 
             break;
 
+        default:
+            return false;
+            break;
 
     }
 
@@ -589,18 +649,10 @@ bool _write_un(const bin_t *value, size_t size, bin_t *data, off_t *pos, off_t e
             for (i = 0; i < size; i++, (*pos)++)
                 *(data + *pos) = *(value + size - i - 1);
 
-#else
-
-#   error "TODO : PDP !"
-
 #endif
 
             break;
 
-        case SRE_MIDDLE:
-            return false;   /* TODO ! */
-            break;
-
         case SRE_BIG:
 
 #if __BYTE_ORDER == __LITTLE_ENDIAN
@@ -613,14 +665,14 @@ bool _write_un(const bin_t *value, size_t size, bin_t *data, off_t *pos, off_t e
             memcpy(&data[*pos], value, size);
             (*pos) += size;
 
-#else
-
-#   error "TODO : PDP !"
-
 #endif
 
             break;
 
+        default:
+            return false;
+            break;
+
     }
 
     return true;
@@ -785,18 +837,10 @@ bool _strtoun(uint8_t n, const char *data, size_t *pos, size_t end, SourceEndian
 
                 *target64 |= ((uint64_t)tmp) << (8 * (n - 1 - i));
 
-#else
-
-#   error "TODO : PDP !"
-
 #endif
 
                 break;
 
-            case SRE_MIDDLE:
-                /* TODO */
-                break;
-
             case SRE_BIG:
 
 #if __BYTE_ORDER == __LITTLE_ENDIAN
@@ -807,14 +851,14 @@ bool _strtoun(uint8_t n, const char *data, size_t *pos, size_t end, SourceEndian
 
                 *target64 |= ((uint64_t)tmp) << (8 * i);
 
-#else
-
-#   error "TODO : PDP !"
-
 #endif
 
                 break;
 
+        default:
+            return false;
+            break;
+
         }
 
     }
diff --git a/src/common/endianness.h b/src/common/endianness.h
index 5ceb2ee..625b7fd 100755
--- a/src/common/endianness.h
+++ b/src/common/endianness.h
@@ -37,12 +37,14 @@
 typedef enum _SourceEndian
 {
     SRE_LITTLE,                             /* Petits boutistes            */
-    SRE_MIDDLE,                             /* Moyens boutistes            */
+    SRE_LITTLE_WORD,                        /* Moyens, façon Honeywell     */
+    SRE_BIG_WORD,                           /* Moyens, façon PDP-11        */
     SRE_BIG                                 /* Gros boutistes              */
 
 } SourceEndian;
 
 
+
 /* --------------------------- CONVERSION ENTRE BOUTISMES --------------------------- */
 
 
diff --git a/tests/analysis/contents/endian.py b/tests/analysis/contents/endian.py
new file mode 100644
index 0000000..209600a
--- /dev/null
+++ b/tests/analysis/contents/endian.py
@@ -0,0 +1,129 @@
+#!/usr/bin/python3-dbg
+# -*- coding: utf-8 -*-
+
+
+# Tests minimalistes pour valider le boutisme des accès mémoire.
+
+
+from chrysacase import ChrysalideTestCase
+from pychrysalide.analysis.contents import FileContent, RestrictedContent
+from pychrysalide.arch import vmpa
+import tempfile
+
+
+class TestEndianness(ChrysalideTestCase):
+    """TestCase for analysis.BinContent."""
+
+    @classmethod
+    def setUpClass(cls):
+
+        super(TestEndianness, cls).setUpClass()
+
+        cls._out = tempfile.NamedTemporaryFile()
+
+        cls._out.write(b'\x01\x02\x03\x04')
+        cls._out.write(b'\x05\x06\x07\x08')
+        cls._out.write(b'\x11\x12\x13\x14')
+        cls._out.write(b'\x15\x16\x17\x18')
+        cls._out.write(b'\x21\x22\x23\x24')
+        cls._out.write(b'\x25\x26\x27\x28')
+        cls._out.write(b'\x31\x32\x33\x34')
+        cls._out.write(b'\x35\x36\x37\x38')
+
+        cls._out.flush()
+
+        cls.log('Using temporary file "%s"' % cls._out.name)
+
+
+    @classmethod
+    def tearDownClass(cls):
+
+        super(TestEndianness, cls).tearDownClass()
+
+        cls.log('Delete file "%s"' % cls._out.name)
+
+        cls._out.close()
+
+
+    def testMiddleEndianness(self):
+        """Test some old endianness."""
+
+        fcnt = FileContent(self._out.name)
+
+        # 16 bits
+
+        start = vmpa(12, vmpa.VMPA_NO_VIRTUAL)
+
+        val = fcnt.read_u16(start, vmpa.SRE_LITTLE_WORD)
+        self.assertEqual(val, 0x1516)
+
+        start = vmpa(12, vmpa.VMPA_NO_VIRTUAL)
+
+        val = fcnt.read_u16(start, vmpa.SRE_BIG_WORD)
+        self.assertEqual(val, 0x1615)
+
+        # 32 bits
+
+        start = vmpa(12, vmpa.VMPA_NO_VIRTUAL)
+
+        val = fcnt.read_u32(start, vmpa.SRE_LITTLE_WORD)
+        self.assertEqual(val, 0x17181516)
+
+        start = vmpa(12, vmpa.VMPA_NO_VIRTUAL)
+
+        val = fcnt.read_u32(start, vmpa.SRE_BIG_WORD)
+        self.assertEqual(val, 0x16151817)
+
+        # 64 bits
+
+        start = vmpa(0, vmpa.VMPA_NO_VIRTUAL)
+
+        val = fcnt.read_u64(start, vmpa.SRE_LITTLE_WORD)
+        self.assertEqual(val, 0x0708050603040102)
+
+        start = vmpa(0, vmpa.VMPA_NO_VIRTUAL)
+
+        val = fcnt.read_u64(start, vmpa.SRE_BIG_WORD)
+        self.assertEqual(val, 0x0201040306050807)
+
+
+    def testEndianness(self):
+        """Test usual endianness."""
+
+        fcnt = FileContent(self._out.name)
+
+        # 16 bits
+
+        start = vmpa(12, vmpa.VMPA_NO_VIRTUAL)
+
+        val = fcnt.read_u16(start, vmpa.SRE_LITTLE)
+        self.assertEqual(val, 0x1615)
+
+        start = vmpa(12, vmpa.VMPA_NO_VIRTUAL)
+
+        val = fcnt.read_u16(start, vmpa.SRE_BIG)
+        self.assertEqual(val, 0x1516)
+
+        # 32 bits
+
+        start = vmpa(12, vmpa.VMPA_NO_VIRTUAL)
+
+        val = fcnt.read_u32(start, vmpa.SRE_LITTLE)
+        self.assertEqual(val, 0x18171615)
+
+        start = vmpa(12, vmpa.VMPA_NO_VIRTUAL)
+
+        val = fcnt.read_u32(start, vmpa.SRE_BIG)
+        self.assertEqual(val, 0x15161718)
+
+        # 64 bits
+
+        start = vmpa(0, vmpa.VMPA_NO_VIRTUAL)
+
+        val = fcnt.read_u64(start, vmpa.SRE_LITTLE)
+        self.assertEqual(val, 0x0807060504030201)
+
+        start = vmpa(0, vmpa.VMPA_NO_VIRTUAL)
+
+        val = fcnt.read_u64(start, vmpa.SRE_BIG)
+        self.assertEqual(val, 0x0102030405060708)
-- 
cgit v0.11.2-87-g4458