summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorCyrille Bagard <nocbos@gmail.com>2021-02-20 22:38:22 (GMT)
committerCyrille Bagard <nocbos@gmail.com>2021-02-20 22:38:22 (GMT)
commit9a080bc3f8184a5663ce42c3c74ae80e1ae598a0 (patch)
treefa80229577a84afd58c1dc81ea599cd67036d771 /src
parent170dc35d87e0a858c5400937a1ee2d2dde7f653a (diff)
Pack and unpack LEB128 values on demand.
Diffstat (limited to 'src')
-rw-r--r--src/common/leb128.c207
-rw-r--r--src/common/leb128.h16
2 files changed, 222 insertions, 1 deletions
diff --git a/src/common/leb128.c b/src/common/leb128.c
index c3f7466..c8d2ace 100644
--- a/src/common/leb128.c
+++ b/src/common/leb128.c
@@ -109,3 +109,210 @@ bool read_leb128(leb128_t *target, const bin_t *data, phys_t *pos, phys_t len)
return (i < 8);
}
+
+
+/******************************************************************************
+* *
+* Paramètres : value = valeur à consigner. *
+* pbuf = tampon de données à constituer. [OUT] *
+* *
+* Description : Encode un nombre non signé encodé au format LEB128. *
+* *
+* Retour : Bilan de l'opération : true en cas de succès, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool pack_uleb128(const uleb128_t *value, packed_buffer_t *pbuf)
+{
+ bool result; /* Bilan à retourner */
+ uleb128_t tmp; /* Valeur modifiable */
+ uint8_t byte; /* Octet à transposer */
+
+ tmp = *value;
+
+ do
+ {
+ byte = (tmp & 0x7f);
+ tmp >>= 7;
+
+ if (tmp != 0)
+ byte |= 0x80;
+
+ result = extend_packed_buffer(pbuf, &byte, sizeof(uint8_t), false);
+
+ }
+ while (result && tmp != 0);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : value = valeur à consigner. *
+* pbuf = tampon de données à constituer. [OUT] *
+* *
+* Description : Encode un nombre signé encodé au format LEB128. *
+* *
+* Retour : Bilan de l'opération : true en cas de succès, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool pack_leb128(const leb128_t *value, packed_buffer_t *pbuf)
+{
+
+ bool result; /* Bilan à retourner */
+ uleb128_t tmp; /* Valeur modifiable */
+ bool more; /* Poursuite des traitements */
+ bool negative; /* Nature de la valeur */
+ uint8_t byte; /* Octet à transposer */
+
+ tmp = *value;
+
+ more = true;
+ negative = (*value < 0);
+
+ while (more)
+ {
+ byte = (tmp & 0x7f);
+ tmp >>= 7;
+
+ /**
+ * Propagation forcée du bit de signe pour les implémentations de
+ * décalage basées sur une opération logique et non arithmétique.
+ */
+
+ if (negative)
+ tmp |= (~0llu << (LEB128_BITS_COUNT - 7));
+
+ /**
+ * Le bit de signe n'est pas le bit de poids fort ici :
+ * On travaille sur 7 bits, donc le masque est 0x40 !
+ */
+
+ if ((tmp == 0 && (byte & 0x40) == 0x00) || (tmp == -1 && (byte & 0x40) == 0x40))
+ more = false;
+
+ else
+ byte |= 0x80;
+
+ result = extend_packed_buffer(pbuf, &byte, sizeof(uint8_t), false);
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : value = valeur à constituer. [OUT] *
+* pbuf = tampon de données à consulter. *
+* *
+* Description : Décode un nombre non signé encodé au format LEB128. *
+* *
+* Retour : Bilan de l'opération : true en cas de succès, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool unpack_uleb128(uleb128_t *value, packed_buffer_t *pbuf)
+{
+ bool result; /* Bilan à retourner */
+ unsigned int shift; /* Décalage à appliquer */
+ uint8_t byte; /* Octet à transposer */
+
+ result = true;
+
+ *value = 0;
+
+ shift = 0;
+
+ while (true)
+ {
+ /* Encodage sur trop d'octets ? */
+ if (shift > (7 * sizeof(uleb128_t)))
+ {
+ result = false;
+ break;
+ }
+
+ result = extract_packed_buffer(pbuf, &byte, sizeof(uint8_t), false);
+ if (!result) break;
+
+ *value |= ((byte & 0x7f) << shift);
+
+ if ((byte & 0x80) == 0x00)
+ break;
+
+ shift += 7;
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : value = valeur à constituer. [OUT] *
+* pbuf = tampon de données à consulter. *
+* *
+* Description : Décode un nombre signé encodé au format LEB128. *
+* *
+* Retour : Bilan de l'opération : true en cas de succès, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool unpack_leb128(leb128_t *value, packed_buffer_t *pbuf)
+{
+ bool result; /* Bilan à retourner */
+ unsigned int shift; /* Décalage à appliquer */
+ uint8_t byte; /* Octet à transposer */
+
+ result = true;
+
+ *value = 0;
+
+ shift = 0;
+
+ do
+ {
+ /* Encodage sur trop d'octets ? */
+ if (shift > (7 * sizeof(leb128_t)))
+ {
+ result = false;
+ break;
+ }
+
+ result = extract_packed_buffer(pbuf, &byte, sizeof(uint8_t), false);
+ if (!result) break;
+
+ *value |= ((byte & 0x7f) << shift);
+
+ shift += 7;
+
+ }
+ while ((byte & 0x80) == 0x80);
+
+ /**
+ * Le bit de signe n'est pas le bit de poids fort ici :
+ * On travaille sur 7 bits, donc le masque est 0x40 !
+ */
+
+ if (shift < LEB128_BITS_COUNT && (byte & 0x40) == 0x40)
+ *value |= (~0llu << shift);
+
+ return result;
+
+}
diff --git a/src/common/leb128.h b/src/common/leb128.h
index 2093ead..ae1078a 100644
--- a/src/common/leb128.h
+++ b/src/common/leb128.h
@@ -29,6 +29,7 @@
#include <stdlib.h>
+#include "packed.h"
#include "../arch/archbase.h"
#include "../arch/vmpa.h"
@@ -39,10 +40,12 @@ typedef uint64_t uleb128_t;
typedef int64_t leb128_t;
+/* Quantité de bits utilisés */
+#define LEB128_BITS_COUNT (sizeof(leb128_t) * 8)
+
/* Récupération de la valeur absolue */
#define leb128_abs(v) llabs(v)
-
/* Valeurs minimales et maximales */
#define ULEB128_MIN UINT64_MIN
#define ULEB128_MAX UINT64_MAX
@@ -56,6 +59,17 @@ bool read_uleb128(uleb128_t *, const bin_t *, phys_t *, phys_t);
/* Lit un nombre signé encodé au format LEB128. */
bool read_leb128(leb128_t *, const bin_t *, phys_t *, phys_t);
+/* Encode un nombre non signé encodé au format LEB128. */
+bool pack_uleb128(const uleb128_t *, packed_buffer_t *);
+
+/* Encode un nombre signé encodé au format LEB128. */
+bool pack_leb128(const leb128_t *, packed_buffer_t *);
+
+/* Décode un nombre non signé encodé au format LEB128. */
+bool unpack_uleb128(uleb128_t *, packed_buffer_t *);
+
+/* Décode un nombre signé encodé au format LEB128. */
+bool unpack_leb128(leb128_t *, packed_buffer_t *);
#endif /* _COMMON_LEB128_H */