Add several memory helpers (required for speed up of string search). (#5372)
* Add function to memcpy memory with offset. * Add count trailing zeros function. * Add function to determine pointer alignment. * Add helper to swap sequences of 2 bytes. * Add helper to swap sequences of 4 bytes. * Print pointer in warning * Fix tests * Use uintptr_t type to prevent undefined behavior. * Remove alignment requirement and rely on malloc promises. * Add in place byte swap functions. * Move the endianness swapping into util/rz_endian * Use GNU builtin __builtin_ctzll/clzll. Also fixes the include guards of __builtin_clzll and handles the undefined case of x == 0 of it. * Add doxygen
This commit is contained in:
parent
976671d660
commit
fdc9ecbacc
10 changed files with 608 additions and 1 deletions
|
|
@ -1813,6 +1813,60 @@ static inline ut64 rz_swap_ut64(ut64 val) {
|
|||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \def rz_swap_2b_ut64
|
||||
* \brief Swaps pairs of 2 bytes in a 64bit value
|
||||
*
|
||||
* # Example
|
||||
*
|
||||
* \code{.c}
|
||||
* ut32 x = 0x8899AABBCCDDEEFF;
|
||||
* ut32 result = 0x9988BBAADDCCFFEE;
|
||||
* assert(rz_swap_2b_ut64(x) == result);
|
||||
* \endcode
|
||||
*/
|
||||
static inline ut64 rz_swap_2b_ut64(ut64 val) {
|
||||
val = ((val & 0xff00ff00ff00ff00) >> 8) | ((val & 0x00ff00ff00ff00ff) << 8);
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
* \def rz_swap_4b_ut64
|
||||
* \brief Swaps pairs of 4 bytes in a 64bit value
|
||||
*
|
||||
* # Example
|
||||
*
|
||||
* \code{.c}
|
||||
* ut32 x = 0x8899AABBCCDDEEFF;
|
||||
* ut32 result = 0xBBAA9988FFEEDDCC;
|
||||
* assert(rz_swap_4b_ut64(x) == result);
|
||||
* \endcode
|
||||
*/
|
||||
static inline ut64 rz_swap_4b_ut64(ut64 val) {
|
||||
val = ((val & 0xff000000ff000000) >> 24) |
|
||||
((val & 0x00ff000000ff0000) >> 8) |
|
||||
((val & 0x0000ff000000ff00) << 8) |
|
||||
((val & 0x000000ff000000ff) << 24);
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
* \def rz_swap_2b_ut32
|
||||
* \brief Swaps pairs of 2 bytes in a 32bit value
|
||||
*
|
||||
* # Example
|
||||
*
|
||||
* \code{.c}
|
||||
* ut32 x = 0xCCDDEEFF;
|
||||
* ut32 result = 0xDDCCFFEE;
|
||||
* assert(rz_swap_2b_ut32(x) == result);
|
||||
* \endcode
|
||||
*/
|
||||
static inline ut32 rz_swap_2b_ut32(ut32 val) {
|
||||
val = ((val & 0xff00ff00) >> 8) | ((val & 0x00ff00ff) << 8);
|
||||
return val;
|
||||
}
|
||||
|
||||
/* Some "secured" functions, to do basic operation (mul, sub, add...) on integers */
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#define st16 short
|
||||
#define ut8 unsigned char
|
||||
#define st8 signed char
|
||||
#define utptr uintptr_t
|
||||
#define boolt int
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@
|
|||
#define HAVE___BUILTIN_BSWAP32 @HAVE___BUILTIN_BSWAP32@
|
||||
#define HAVE___BUILTIN_BSWAP64 @HAVE___BUILTIN_BSWAP64@
|
||||
#define HAVE___BUILTIN_CLZLL @HAVE___BUILTIN_CLZLL@
|
||||
#define HAVE___BUILTIN_CTZLL @HAVE___BUILTIN_CTZLL@
|
||||
#define HAVE_POSIX_MEMALIGN @HAVE_POSIX_MEMALIGN@
|
||||
#define HAVE__ALIGNED_MALLOC @HAVE__ALIGNED_MALLOC@
|
||||
|
||||
|
|
|
|||
|
|
@ -33,13 +33,63 @@ DEFINE_COUNT_ONES(ut32);
|
|||
DEFINE_COUNT_ONES(ut16);
|
||||
DEFINE_COUNT_ONES(ut8);
|
||||
|
||||
/**
|
||||
* \brief Count trailing zeros of \p v.
|
||||
* If v == 0 it returns 64.
|
||||
*
|
||||
* \param v The value to count the trailing zeros for.
|
||||
*
|
||||
* \return The number of trailing zeros.
|
||||
*/
|
||||
static inline size_t rz_bits_trailing_zeros(ut64 v) {
|
||||
if (v == 0) {
|
||||
return 64;
|
||||
}
|
||||
#if HAVE___BUILTIN_CTZLL
|
||||
return __builtin_ctzll(v);
|
||||
#else
|
||||
// src: https://graphics.stanford.edu/~seander/bithacks.html#ZerosOnRightBinSearch
|
||||
size_t c;
|
||||
if (v & 0x1) {
|
||||
// special case for odd v (assumed to happen half of the time)
|
||||
return 0;
|
||||
}
|
||||
c = 1;
|
||||
if ((v & 0xffffffff) == 0) {
|
||||
v >>= 32;
|
||||
c += 32;
|
||||
}
|
||||
if ((v & 0xffff) == 0) {
|
||||
v >>= 16;
|
||||
c += 16;
|
||||
}
|
||||
if ((v & 0xff) == 0) {
|
||||
v >>= 8;
|
||||
c += 8;
|
||||
}
|
||||
if ((v & 0xf) == 0) {
|
||||
v >>= 4;
|
||||
c += 4;
|
||||
}
|
||||
if ((v & 0x3) == 0) {
|
||||
v >>= 2;
|
||||
c += 2;
|
||||
}
|
||||
c -= v & 0x1;
|
||||
return c;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get the number of leading zeros of a 64-bit integer in binary representation.
|
||||
* \param x the 64-bit integer
|
||||
* \return the number of leading zeros
|
||||
*/
|
||||
static inline int rz_bits_leading_zeros(ut64 x) {
|
||||
#if HAS___BUILTIN_CLZLL
|
||||
if (x == 0) {
|
||||
return 64;
|
||||
}
|
||||
#if HAVE___BUILTIN_CLZLL
|
||||
return __builtin_clzll(x);
|
||||
#else
|
||||
int n = 0;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#ifndef RZ_MEM_H
|
||||
#define RZ_MEM_H
|
||||
|
||||
#include <rz_util/rz_bits.h>
|
||||
#include <rz_types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
@ -37,6 +38,25 @@ RZ_API int rz_mem_count(const ut8 **addr);
|
|||
RZ_API bool rz_mem_is_printable(const ut8 *a, int la);
|
||||
RZ_API bool rz_mem_is_zero(const ut8 *b, int l);
|
||||
RZ_API ut64 rz_mem_align_padding(const ut64 address, ut64 alignment);
|
||||
RZ_API RZ_OWN ut8 *rz_mem_copy_offset(const ut8 *buf, size_t buf_size, size_t offset);
|
||||
RZ_API RZ_OWN ut8 *rz_mem_swap_bytes_2(RZ_NONNULL const ut8 *buf, size_t buf_size);
|
||||
RZ_API RZ_OWN ut8 *rz_mem_swap_bytes_2_inplace(RZ_OUT RZ_NONNULL ut8 *buf, size_t buf_size);
|
||||
RZ_API RZ_OWN ut8 *rz_mem_swap_bytes_4(RZ_NONNULL const ut8 *buf, size_t buf_size);
|
||||
RZ_API RZ_OWN ut8 *rz_mem_swap_bytes_4_inplace(RZ_OUT RZ_NONNULL ut8 *buf, size_t buf_size);
|
||||
|
||||
/**
|
||||
* \brief Returns the alignment of the \p ptr.
|
||||
*
|
||||
* \param ptr The pointer to get the alignment for.
|
||||
*
|
||||
* \return Returns the pointer alignment or UT64_MAX if \p ptr == NULL or ((utptr) ptr) == 0.
|
||||
*/
|
||||
static inline ut64 rz_mem_ptr_alignment(RZ_NONNULL const void *ptr) {
|
||||
if (ptr == NULL || ((utptr)ptr) == 0) {
|
||||
return UT64_MAX;
|
||||
}
|
||||
return 1ull << rz_bits_trailing_zeros((utptr)ptr);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
|||
242
librz/util/mem.c
242
librz/util/mem.c
|
|
@ -331,3 +331,245 @@ RZ_API void rz_mem_memzero(void *dst, size_t l) {
|
|||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Makes a copy of the buffer \p buf but starts copying data at \p offset.
|
||||
* That is: `rz_mem_align_byte(buf, n, i)` will return a copy of `buf[i:n]`.
|
||||
* The bytes `[n - i:n]` of the returned buffer are set to 0x00.
|
||||
*
|
||||
* \param buf The buffer to copy.
|
||||
* \param buf_size The size of \p buf in bytes. If 0, this function just performce a memcpy.
|
||||
* \param offset The offset to start copying from. If larger than \p buf_size,
|
||||
* it returns a zeroed buffer of size \p buf_size.
|
||||
*
|
||||
* \return The copied buffer or NULL in case of failure. If \p offset >= \p buf_size
|
||||
* the returned buffer is all zeros.
|
||||
*
|
||||
* NOTE: This function is useful to align the data in \p buf to a certain offset.
|
||||
* E.g. reading ut64 values from \p buf + 3 would be undefined behavior and fail under certain conditions.
|
||||
* Instead this function can be used to get a copy of the buffer at this offset:
|
||||
*
|
||||
* Example:
|
||||
* ```c
|
||||
* // This is undefined behavior, because the memory access is misaligned for ut64 values.
|
||||
* ut64 x = *((ut64 *)buf + 3);
|
||||
*
|
||||
* // Instead you can align buf with this function:
|
||||
* ut8 *out = rz_mem_align_byte(buf, buf_size, 3);
|
||||
* ut64 v = *((ut64 *)out);
|
||||
* ```
|
||||
*/
|
||||
RZ_API RZ_OWN ut8 *rz_mem_copy_offset(const ut8 *buf, size_t buf_size, size_t offset) {
|
||||
rz_return_val_if_fail(buf && buf_size > 0, NULL);
|
||||
ut8 *dst = RZ_NEWS0(ut8, buf_size);
|
||||
if (offset >= buf_size) {
|
||||
return dst;
|
||||
}
|
||||
if (!rz_mem_copy(dst, buf_size + offset, buf + offset, buf_size - offset)) {
|
||||
free(dst);
|
||||
return NULL;
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Swaps the bytes in 2 byte blocks from the given buffer and returns
|
||||
* the result.
|
||||
* Remainders of less than 2 bytes at the end of the buffer won't be swapped.
|
||||
*
|
||||
* \param buf The input buffer.
|
||||
* \param buf_size The size of the input buffer. Must be greater than 0.
|
||||
*
|
||||
* \return A clone of the input buffer with swapped bytes or NULL in case of failure.
|
||||
*
|
||||
* NOTE: This function can be used to change the endianness of 2 byte values
|
||||
* in the given buffer.
|
||||
*
|
||||
* Examples:
|
||||
* ```c
|
||||
* const ut8 a[4] = { 0xff, 0x00, 0x99, 0x00 };
|
||||
* const ut8 b[4] = { 0x00, 0xff, 0x00, 0x99 };
|
||||
* ut8 *swapped = rz_mem_swap_bytes_2(a);
|
||||
* assert(memcmp(swapped, b, sizeof(a)) == 0);
|
||||
* ```
|
||||
*
|
||||
* ```c
|
||||
* const ut8 a[4] = { 0xff, 0x00, 0x99, 0x00, 0x11 };
|
||||
* const ut8 b[4] = { 0x00, 0xff, 0x00, 0x99, 0x11 };
|
||||
* ut8 *swapped = rz_mem_swap_bytes_2(a);
|
||||
* assert(memcmp(swapped, b, sizeof(a)) == 0);
|
||||
* ```
|
||||
*/
|
||||
RZ_API RZ_OWN ut8 *rz_mem_swap_bytes_2(RZ_NONNULL const ut8 *buf, size_t buf_size) {
|
||||
rz_return_val_if_fail(buf && buf_size != 0, NULL);
|
||||
ut8 *dst = RZ_NEWS0(ut8, buf_size);
|
||||
if (!dst) {
|
||||
return NULL;
|
||||
}
|
||||
if (!rz_mem_copy(dst, buf_size, buf, buf_size)) {
|
||||
free(dst);
|
||||
return NULL;
|
||||
}
|
||||
return rz_mem_swap_bytes_2_inplace(dst, buf_size);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Swaps the bytes in 2 byte blocks from the given buffer and returns
|
||||
* the result.
|
||||
* Remainders of less than 2 bytes at the end of the buffer won't be swapped.
|
||||
*
|
||||
* \param buf The input buffer.
|
||||
* \param buf_size The size of the input buffer. Must be greater than 0.
|
||||
*
|
||||
* \return A clone of the input buffer with swapped bytes or NULL in case of failure.
|
||||
*
|
||||
* NOTE: This function can be used to change the endianness of 2 byte values
|
||||
* in the given buffer.
|
||||
*
|
||||
* Examples:
|
||||
* ```c
|
||||
* ut8 a[4] = { 0xff, 0x00, 0x99, 0x00 };
|
||||
* const ut8 b[4] = { 0x00, 0xff, 0x00, 0x99 };
|
||||
* ut8 *swapped = rz_mem_swap_bytes_2(a);
|
||||
* assert(a == swapped);
|
||||
* assert(memcmp(swapped, b, sizeof(a)) == 0);
|
||||
* ```
|
||||
*
|
||||
* ```c
|
||||
* ut8 a[4] = { 0xff, 0x00, 0x99, 0x00, 0x11 };
|
||||
* const ut8 b[4] = { 0x00, 0xff, 0x00, 0x99, 0x11 };
|
||||
* ut8 *swapped = rz_mem_swap_bytes_2(a);
|
||||
* assert(a == swapped);
|
||||
* assert(memcmp(swapped, b, sizeof(a)) == 0);
|
||||
* ```
|
||||
*/
|
||||
RZ_API RZ_OWN ut8 *rz_mem_swap_bytes_2_inplace(RZ_OUT RZ_NONNULL ut8 *dst, size_t buf_size) {
|
||||
rz_return_val_if_fail(dst && buf_size, NULL);
|
||||
size_t al = rz_mem_ptr_alignment(dst);
|
||||
if (al < 2) {
|
||||
// malloc guarantees to return an aligned pointer for all data which fits
|
||||
// into the allocated memory.
|
||||
// So, if the pointer is only aligned to less than 2 bytes,
|
||||
// it means buf_size was == 1.
|
||||
// Hence we return simply a clone of the buffer.
|
||||
return dst;
|
||||
}
|
||||
|
||||
ut64 *dst_64 = (ut64 *)dst;
|
||||
while (buf_size >= 8) {
|
||||
*dst_64 = rz_swap_2b_ut64(*dst_64);
|
||||
dst_64++;
|
||||
buf_size -= 8;
|
||||
}
|
||||
ut32 *dst_32 = (ut32 *)dst_64;
|
||||
while (buf_size >= 4) {
|
||||
*dst_32 = rz_swap_2b_ut32(*dst_32);
|
||||
dst_32++;
|
||||
buf_size -= 4;
|
||||
}
|
||||
ut16 *dst_16 = (ut16 *)dst_32;
|
||||
while (buf_size >= 2) {
|
||||
*dst_16 = rz_swap_ut16(*dst_16);
|
||||
dst_16++;
|
||||
buf_size -= 2;
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Swaps the bytes in 4 byte blocks from the given buffer and returns
|
||||
* the result.
|
||||
* Remainders of less than 4 bytes at the end of the buffer won't be swapped.
|
||||
*
|
||||
* \param buf The input buffer.
|
||||
* \param buf_size The size of the input buffer. Must be greater than 0.
|
||||
*
|
||||
* \return A clone of the input buffer with swapped bytes or NULL in case of failure.
|
||||
*
|
||||
* NOTE: This function can be used to change the endianness of 4 byte values
|
||||
* in the given buffer.
|
||||
*
|
||||
* Examples:
|
||||
* ```c
|
||||
* const ut8 a[4] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 };
|
||||
* const ut8 b[4] = { 0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 0x05, 0x04 };
|
||||
* ut8 *swapped = rz_mem_swap_bytes_4(a);
|
||||
* assert(memcmp(swapped, b, sizeof(a)) == 0);
|
||||
* ```
|
||||
*
|
||||
* ```c
|
||||
* const ut8 a[4] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0xff, 0xfe };
|
||||
* const ut8 b[4] = { 0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 0x05, 0x04, 0xff, 0xfe };
|
||||
* ut8 *swapped = rz_mem_swap_bytes_4(a);
|
||||
* assert(memcmp(swapped, b, sizeof(a)) == 0);
|
||||
* ```
|
||||
*/
|
||||
RZ_API RZ_OWN ut8 *rz_mem_swap_bytes_4(RZ_NONNULL const ut8 *buf, size_t buf_size) {
|
||||
rz_return_val_if_fail(buf && buf_size != 0, NULL);
|
||||
ut8 *dst = RZ_NEWS0(ut8, buf_size);
|
||||
if (!dst) {
|
||||
return NULL;
|
||||
}
|
||||
if (!rz_mem_copy(dst, buf_size, buf, buf_size)) {
|
||||
free(dst);
|
||||
return NULL;
|
||||
}
|
||||
return rz_mem_swap_bytes_4_inplace(dst, buf_size);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Swaps the bytes in 4 byte blocks from the given buffer and returns
|
||||
* the result.
|
||||
* Remainders of less than 4 bytes at the end of the buffer won't be swapped.
|
||||
*
|
||||
* \param buf The input buffer.
|
||||
* \param buf_size The size of the input buffer. Must be greater than 0.
|
||||
*
|
||||
* \return The input buffer with swapped bytes or NULL in case of failure.
|
||||
*
|
||||
* NOTE: This function can be used to change the endianness of 4 byte values
|
||||
* in the given buffer.
|
||||
*
|
||||
* Examples:
|
||||
* ```c
|
||||
* ut8 a[4] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 };
|
||||
* const ut8 b[4] = { 0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 0x05, 0x04 };
|
||||
* ut8 *swapped = rz_mem_swap_bytes_4(a);
|
||||
* assert(a == swapped);
|
||||
* assert(memcmp(swapped, b, sizeof(a)) == 0);
|
||||
* ```
|
||||
*
|
||||
* ```c
|
||||
* ut8 a[4] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0xff, 0xfe };
|
||||
* const ut8 b[4] = { 0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 0x05, 0x04, 0xff, 0xfe };
|
||||
* ut8 *swapped = rz_mem_swap_bytes_4(a);
|
||||
* assert(a == swapped);
|
||||
* assert(memcmp(swapped, b, sizeof(a)) == 0);
|
||||
* ```
|
||||
*/
|
||||
RZ_API RZ_OWN ut8 *rz_mem_swap_bytes_4_inplace(RZ_OUT RZ_NONNULL ut8 *dst, size_t buf_size) {
|
||||
rz_return_val_if_fail(dst && buf_size, NULL);
|
||||
size_t al = rz_mem_ptr_alignment(dst);
|
||||
if (al < 4) {
|
||||
// malloc guarantees to return an aligned pointer for all data which fits
|
||||
// into the allocated memory.
|
||||
// So, if the pointer is only aligned to less than 4 bytes,
|
||||
// it means buf_size was <= 3.
|
||||
// Hence we return simply a clone of the buffer.
|
||||
return dst;
|
||||
}
|
||||
|
||||
ut64 *dst_64 = (ut64 *)dst;
|
||||
while (buf_size >= 8) {
|
||||
*dst_64 = rz_swap_4b_ut64(*dst_64);
|
||||
dst_64++;
|
||||
buf_size -= 8;
|
||||
}
|
||||
ut32 *dst_32 = (ut32 *)dst_64;
|
||||
while (buf_size >= 4) {
|
||||
*dst_32 = rz_swap_ut32(*dst_32);
|
||||
dst_32++;
|
||||
buf_size -= 4;
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -500,6 +500,7 @@ foreach it : ccs
|
|||
['__builtin_bswap32', '', []],
|
||||
['__builtin_bswap64', '', []],
|
||||
['__builtin_clzll', '', []],
|
||||
['__builtin_ctzll', '', []],
|
||||
['posix_memalign', '#include <stdlib.h>', []],
|
||||
['_aligned_malloc', '#include <malloc.h>', []],
|
||||
]
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <rz_util.h>
|
||||
#include "minunit.h"
|
||||
#include "rz_util/rz_bits.h"
|
||||
|
||||
bool test_rz_bits_count(void) {
|
||||
mu_assert_eq(rz_bits_count_ones_ut64(0xffffffffffffffff), 64, "Bit count mismatch.");
|
||||
|
|
@ -35,6 +36,15 @@ bool test_rz_bits_count(void) {
|
|||
mu_end;
|
||||
}
|
||||
|
||||
bool test_rz_bits_trailing_zero(void) {
|
||||
mu_assert_eq(rz_bits_trailing_zeros(0), 64, "Bit count mismatch.");
|
||||
for (size_t i = 1, j = 0; i != 0; i <<= 1, j++) {
|
||||
mu_assert_eq(rz_bits_trailing_zeros(i), j, "Bit count mismatch.");
|
||||
}
|
||||
|
||||
mu_end;
|
||||
}
|
||||
|
||||
bool test_rz_bits_spread(void) {
|
||||
mu_assert_eq(rz_bits_spread(0xffffffffffffffff, 0xffffffffffffffff), 0xffffffffffffffff, "Spread mismatch.");
|
||||
mu_assert_eq(rz_bits_spread(0, 0xffffffffffffffff), 0, "Spread mismatch.");
|
||||
|
|
@ -52,6 +62,7 @@ bool test_rz_bits_spread(void) {
|
|||
bool all_tests() {
|
||||
mu_run_test(test_rz_bits_count);
|
||||
mu_run_test(test_rz_bits_spread);
|
||||
mu_run_test(test_rz_bits_trailing_zero);
|
||||
|
||||
return tests_passed != tests_run;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -364,6 +364,20 @@ bool test_rz_swap_ut64(void) {
|
|||
mu_end;
|
||||
}
|
||||
|
||||
bool test_rz_swap_4b_ut64(void) {
|
||||
ut64 a = 0x1122334455667788;
|
||||
ut64 b = rz_swap_4b_ut64(a);
|
||||
mu_assert_eq(b, 0x4433221188776655, "rz_swap_4b_ut64");
|
||||
mu_end;
|
||||
}
|
||||
|
||||
bool test_rz_swap_2b_ut64(void) {
|
||||
ut64 a = 0x1122334455667788;
|
||||
ut64 b = rz_swap_2b_ut64(a);
|
||||
mu_assert_eq(b, 0x2211443366558877, "rz_swap_2b_ut64");
|
||||
mu_end;
|
||||
}
|
||||
|
||||
bool test_rz_swap_ut32(void) {
|
||||
ut32 a = 0x11223344;
|
||||
ut32 b = rz_swap_ut32(a);
|
||||
|
|
@ -371,6 +385,13 @@ bool test_rz_swap_ut32(void) {
|
|||
mu_end;
|
||||
}
|
||||
|
||||
bool test_rz_swap_2b_ut32(void) {
|
||||
ut32 a = 0x11223344;
|
||||
ut32 b = rz_swap_2b_ut32(a);
|
||||
mu_assert_eq(b, 0x22114433, "rz_swap_2b_ut32");
|
||||
mu_end;
|
||||
}
|
||||
|
||||
bool test_rz_swap_ut16(void) {
|
||||
ut16 a = 0x1122;
|
||||
ut16 b = rz_swap_ut16(a);
|
||||
|
|
@ -494,7 +515,10 @@ int all_tests() {
|
|||
|
||||
mu_run_test(test_endian);
|
||||
mu_run_test(test_rz_swap_ut64);
|
||||
mu_run_test(test_rz_swap_4b_ut64);
|
||||
mu_run_test(test_rz_swap_2b_ut64);
|
||||
mu_run_test(test_rz_swap_ut32);
|
||||
mu_run_test(test_rz_swap_2b_ut32);
|
||||
mu_run_test(test_rz_swap_ut16);
|
||||
mu_run_test(test_be);
|
||||
mu_run_test(test_le);
|
||||
|
|
|
|||
|
|
@ -27,8 +27,211 @@ bool test_rz_mem_align_padding(void) {
|
|||
mu_end;
|
||||
}
|
||||
|
||||
bool test_rz_mem_align_byte(void) {
|
||||
const ut8 one_byte[1] = { 0xff };
|
||||
const ut8 one_byte_a_2[1] = { 0x00 };
|
||||
const ut8 two_bytes[2] = { 0x00, 0x01 };
|
||||
const ut8 two_bytes_a_2[2] = { 0x01, 0x00 };
|
||||
const ut8 two_bytes_a_3[2] = { 0x00, 0x00 };
|
||||
const ut8 two_bytes_a_8[2] = { 0x00, 0x00 };
|
||||
const ut8 seven_bytes[7] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 };
|
||||
const ut8 seven_bytes_a_2[7] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x00 };
|
||||
const ut8 seven_bytes_a_3[7] = { 0x02, 0x03, 0x04, 0x05, 0x06, 0x00, 0x00 };
|
||||
const ut8 seven_bytes_a_7[7] = { 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
const ut8 seven_bytes_a_8[7] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
const ut8 eight_bytes[8] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 };
|
||||
const ut8 eight_bytes_a_2[8] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x00 };
|
||||
const ut8 eight_bytes_a_8[8] = { 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
const ut8 nine_bytes[9] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
|
||||
const ut8 nine_bytes_a_8[9] = { 0x07, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
|
||||
// clang-format off
|
||||
const ut8 block[0x20] = {
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
||||
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
};
|
||||
const ut8 block_a_2[0x20] = {
|
||||
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
|
||||
0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
|
||||
0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
|
||||
0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x00
|
||||
};
|
||||
const ut8 block_a_8[0x20] = {
|
||||
0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
|
||||
0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
|
||||
0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e,
|
||||
0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
ut8 *test_out;
|
||||
|
||||
#define TEST(input, expected, alignment, msg) \
|
||||
test_out = rz_mem_copy_offset(input, sizeof(input), alignment); \
|
||||
mu_assert_notnull(test_out, "NULL check failed"); \
|
||||
mu_assert_memeq(test_out, expected, sizeof(expected), msg); \
|
||||
mu_assert_eq(((ut64)test_out) % 8, 0, "Address is not aligned to 8."); \
|
||||
free(test_out);
|
||||
|
||||
TEST(one_byte, one_byte, 0, "Alignment of 1 should be memcpy")
|
||||
TEST(block, block, 0, "Alignment of 1 should be memcpy")
|
||||
|
||||
TEST(two_bytes, two_bytes_a_3, 3, "Alignment larger than buffer")
|
||||
TEST(two_bytes, two_bytes_a_8, 8, "Alignment larger than buffer")
|
||||
|
||||
TEST(one_byte, one_byte_a_2, 2, "Invalid alignment result")
|
||||
|
||||
TEST(two_bytes, two_bytes_a_2, 1, "Invalid alignment result")
|
||||
|
||||
TEST(seven_bytes, seven_bytes_a_2, 1, "Invalid alignment result")
|
||||
TEST(seven_bytes, seven_bytes_a_3, 2, "Invalid alignment result")
|
||||
TEST(seven_bytes, seven_bytes_a_7, 6, "Invalid alignment result")
|
||||
TEST(seven_bytes, seven_bytes_a_8, 7, "Invalid alignment result")
|
||||
|
||||
TEST(eight_bytes, eight_bytes_a_2, 1, "Invalid alignment result")
|
||||
TEST(eight_bytes, eight_bytes_a_8, 7, "Invalid alignment result")
|
||||
|
||||
TEST(nine_bytes, nine_bytes_a_8, 7, "Invalid alignment result")
|
||||
|
||||
TEST(block, block_a_2, 1, "Invalid alignment result")
|
||||
TEST(block, block_a_8, 7, "Invalid alignment result")
|
||||
|
||||
#undef TEST
|
||||
|
||||
mu_end;
|
||||
}
|
||||
|
||||
bool test_rz_mem_ptr_alignment(void) {
|
||||
mu_assert_eq(rz_mem_ptr_alignment(NULL), UT64_MAX, "Error case failed.");
|
||||
mu_assert_eq(rz_mem_ptr_alignment((void *)0), UT64_MAX, "Error case failed.");
|
||||
for (ut64 i = 1; i != 0; i <<= 1) {
|
||||
mu_assert_eq(rz_mem_ptr_alignment((void *)i), i, "Pointer alignment mismatches.");
|
||||
}
|
||||
|
||||
mu_end;
|
||||
}
|
||||
|
||||
bool test_rz_mem_byte_swap_2(void) {
|
||||
const ut8 buf_1[] = { 0xff };
|
||||
const ut8 buf_1s[] = { 0xff };
|
||||
const ut8 buf_2[] = { 0xff, 0x00 };
|
||||
const ut8 buf_2s[] = { 0x00, 0xff };
|
||||
const ut8 buf_3[] = { 0xff, 0x00, 0xfe };
|
||||
const ut8 buf_3s[] = { 0x00, 0xff, 0xfe };
|
||||
const ut8 buf_4[] = { 0xff, 0x00, 0xfe, 0x00 };
|
||||
const ut8 buf_4s[] = { 0x00, 0xff, 0x00, 0xfe };
|
||||
const ut8 buf_5[] = { 0xff, 0x00, 0xfe, 0x00, 0xfd };
|
||||
const ut8 buf_5s[] = { 0x00, 0xff, 0x00, 0xfe, 0xfd };
|
||||
const ut8 buf_8[] = { 0xff, 0x00, 0xfe, 0x00, 0xfd, 0x00, 0xfc, 0x00 };
|
||||
const ut8 buf_8s[] = { 0x00, 0xff, 0x00, 0xfe, 0x00, 0xfd, 0x00, 0xfc };
|
||||
const ut8 buf_9[] = { 0xff, 0x00, 0xfe, 0x00, 0xfd, 0x00, 0xfc, 0x00, 0xfb };
|
||||
const ut8 buf_9s[] = { 0x00, 0xff, 0x00, 0xfe, 0x00, 0xfd, 0x00, 0xfc, 0xfb };
|
||||
|
||||
// clang-format off
|
||||
const ut8 block_32[] = {
|
||||
0xff, 0x00, 0xfe, 0x00, 0xfd, 0x00, 0xfc, 0x00,
|
||||
0xfb, 0x00, 0xfa, 0x00, 0xf9, 0x00, 0xf8, 0x00,
|
||||
0xf7, 0x00, 0xf6, 0x00, 0xf5, 0x00, 0xf4, 0x00,
|
||||
0xf3, 0x00, 0xf2, 0x00, 0xf1, 0x00, 0xf0, 0x00
|
||||
};
|
||||
const ut8 block_32s[] = {
|
||||
0x00, 0xff, 0x00, 0xfe, 0x00, 0xfd, 0x00, 0xfc,
|
||||
0x00, 0xfb, 0x00, 0xfa, 0x00, 0xf9, 0x00, 0xf8,
|
||||
0x00, 0xf7, 0x00, 0xf6, 0x00, 0xf5, 0x00, 0xf4,
|
||||
0x00, 0xf3, 0x00, 0xf2, 0x00, 0xf1, 0x00, 0xf0
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
ut8 *test_out;
|
||||
|
||||
#define TEST(input, expected, msg) \
|
||||
test_out = rz_mem_swap_bytes_2(input, sizeof(input)); \
|
||||
mu_assert_notnull(test_out, "NULL check failed"); \
|
||||
mu_assert_memeq(test_out, expected, sizeof(expected), msg); \
|
||||
free(test_out);
|
||||
|
||||
TEST(buf_1, buf_1s, "Swap failed.");
|
||||
TEST(buf_2, buf_2s, "Swap failed.");
|
||||
TEST(buf_3, buf_3s, "Swap failed.");
|
||||
TEST(buf_4, buf_4s, "Swap failed.");
|
||||
TEST(buf_5, buf_5s, "Swap failed.");
|
||||
TEST(buf_8, buf_8s, "Swap failed.");
|
||||
TEST(buf_9, buf_9s, "Swap failed.");
|
||||
TEST(block_32, block_32s, "Swap failed.");
|
||||
|
||||
#undef TEST
|
||||
|
||||
mu_end;
|
||||
}
|
||||
|
||||
bool test_rz_mem_byte_swap_4(void) {
|
||||
const ut8 buf_1[] = { 0xff };
|
||||
const ut8 buf_1s[] = { 0xff };
|
||||
const ut8 buf_3[] = { 0xff, 0x00, 0xfe };
|
||||
const ut8 buf_3s[] = { 0xff, 0x00, 0xfe };
|
||||
const ut8 buf_4[] = { 0x00, 0x01, 0x02, 0x03 };
|
||||
const ut8 buf_4s[] = { 0x03, 0x02, 0x01, 0x00 };
|
||||
const ut8 buf_5[] = { 0x00, 0x01, 0x02, 0x03, 0x04 };
|
||||
const ut8 buf_5s[] = { 0x03, 0x02, 0x01, 0x00, 0x04 };
|
||||
const ut8 buf_8[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 };
|
||||
const ut8 buf_8s[] = { 0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 0x05, 0x04 };
|
||||
const ut8 buf_9[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0xff };
|
||||
const ut8 buf_9s[] = { 0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 0x05, 0x04, 0xff };
|
||||
|
||||
// clang-format off
|
||||
const ut8 block_34[] = {
|
||||
0x00, 0x01, 0x02, 0x03,
|
||||
0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b,
|
||||
0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13,
|
||||
0x14, 0x15, 0x16, 0x17,
|
||||
0x18, 0x19, 0x1a, 0x1b,
|
||||
0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x55, 0x44
|
||||
};
|
||||
const ut8 block_34s[] = {
|
||||
0x03, 0x02, 0x01, 0x00,
|
||||
0x07, 0x06, 0x05, 0x04,
|
||||
0x0b, 0x0a, 0x09, 0x08,
|
||||
0x0f, 0x0e, 0x0d, 0x0c,
|
||||
0x13, 0x12, 0x11, 0x10,
|
||||
0x17, 0x16, 0x15, 0x14,
|
||||
0x1b, 0x1a, 0x19, 0x18,
|
||||
0x1f, 0x1e, 0x1d, 0x1c,
|
||||
0x55, 0x44
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
ut8 *test_out;
|
||||
|
||||
#define TEST(input, expected, msg) \
|
||||
test_out = rz_mem_swap_bytes_4(input, sizeof(input)); \
|
||||
mu_assert_notnull(test_out, "NULL check failed"); \
|
||||
mu_assert_memeq(test_out, expected, sizeof(expected), msg); \
|
||||
free(test_out);
|
||||
|
||||
TEST(buf_1, buf_1s, "Swap failed.");
|
||||
TEST(buf_3, buf_3s, "Swap failed.");
|
||||
TEST(buf_4, buf_4s, "Swap failed.");
|
||||
TEST(buf_5, buf_5s, "Swap failed.");
|
||||
TEST(buf_8, buf_8s, "Swap failed.");
|
||||
TEST(buf_9, buf_9s, "Swap failed.");
|
||||
TEST(block_34, block_34s, "Swap failed.");
|
||||
|
||||
#undef TEST
|
||||
|
||||
mu_end;
|
||||
}
|
||||
|
||||
bool all_tests() {
|
||||
mu_run_test(test_rz_mem_align_padding);
|
||||
mu_run_test(test_rz_mem_align_byte);
|
||||
mu_run_test(test_rz_mem_ptr_alignment);
|
||||
mu_run_test(test_rz_mem_byte_swap_2);
|
||||
mu_run_test(test_rz_mem_byte_swap_4);
|
||||
|
||||
return tests_passed != tests_run;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue