From 3519a3d9be3c578a9b98a921aa1545922ba7cd2e Mon Sep 17 00:00:00 2001 From: Martine Lenders Date: Mon, 27 Oct 2014 19:03:04 +0100 Subject: [PATCH] sys: Initial import of analytical object dump (od) module --- sys/Makefile | 3 + sys/include/od.h | 161 +++++++++++++++++++++++ sys/od/Makefile | 1 + sys/od/od.c | 336 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 501 insertions(+) create mode 100644 sys/include/od.h create mode 100644 sys/od/Makefile create mode 100644 sys/od/od.c diff --git a/sys/Makefile b/sys/Makefile index ebbb3bd0c17e..effe97398c7b 100644 --- a/sys/Makefile +++ b/sys/Makefile @@ -10,6 +10,9 @@ endif ifneq (,$(filter lib,$(USEMODULE))) DIRS += lib endif +ifneq (,$(filter od,$(USEMODULE))) + DIRS += od +endif ifneq (,$(filter ping,$(USEMODULE))) DIRS += ping endif diff --git a/sys/include/od.h b/sys/include/od.h new file mode 100644 index 000000000000..00dadf90f581 --- /dev/null +++ b/sys/include/od.h @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2014 Martin Lenders + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @defgroup sys_od Object dump + * @ingroup sys + * @brief Allows to print out data dumps of memory regions in a similar fashion + * to the UNIX's + * + * od + * tool + * + * @see + * od(1) + * + * @{ + * + * @file od.h + * + * @author Martine Lenders + */ +#ifndef __OD_H_ +#define __OD_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/** + * @brief Bit-mask to extract address offset format settings from flags + */ +#define OD_FLAGS_ADDRESS_MASK (0xc000) + +/** + * @brief Bit-mask to extract byte format settings from flags + */ +#define OD_FLAGS_BYTES_MASK (0x3e00) + +/** + * @brief Bit-mask to extract length information for byte format from flags + */ +#define OD_FLAGS_LENGTH_MASK (0x00f7) + +/** + * @anchor od_flags_address + * @name Address offset format flags + * @brief Flags to define format of the address offset + * @{ + */ +#define OD_FLAGS_ADDRESS_OCTAL (0x0000) /**< octal address offset */ +#define OD_FLAGS_ADDRESS_HEX (0x4000) /**< hexadecimal address offset */ +#define OD_FLAGS_ADDRESS_DECIMAL (0x8000) /**< decimal address offset */ +#define OD_FLAGS_ADDRESS_NONE (0xc000) /**< no address offset */ +/** @} */ + +/** + * @anchor od_flags_bytes + * @name Bytes format flags + * @brief Flags to define format of the byte output + * @{ + */ +/** + * @brief Print `LENGTH` bytes as `LENGTH`-wide octal integer (`LENGTH` is defined + * in the lower significant byte of the flags) + */ +#define OD_FLAGS_BYTES_OCTAL (0x0000) + +/** + * @brief Print bytes as their represented character in ASCII + */ +#define OD_FLAGS_BYTES_CHAR (0x2000) + +/** + * @brief Print `LENGTH` bytes as `LENGTH`-wide decimal integer (`LENGTH` is + * defined in the lower significant byte of the flags) + */ +#define OD_FLAGS_BYTES_INT (0x1000) + +/** + * @brief Alias for @ref OD_FLAGS_BYTES_INT + */ +#define OD_FLAGS_BYTES_DECIMAL (OD_FLAGS_BYTES_INT) + +/* XXX: No float support for now, but reserved 0x0800 for this */ + +/** + * @brief Print `LENGTH` bytes as `LENGTH`-wide decimal unsigned integer + * (`LENGTH` is defined in the lower significant byte of the flags) + */ +#define OD_FLAGS_BYTES_UINT (0x0400) + +/** + * @brief Print `LENGTH` bytes as `LENGTH`-wide hexadecimal integer + * (`LENGTH` is defined in the lower significant byte of the flags) + */ +#define OD_FLAGS_BYTES_HEX (0x0200) + +/** @} */ + + +/** + * @anchor od_flags_length + * @name Bytes format length flags + * @brief Flags to define format length of the byte output + * @{ + */ +#define OD_FLAGS_LENGTH_1 (0x0010) /**< 1 byte */ +#define OD_FLAGS_LENGTH_2 (0x0020) /**< 2 byte */ +#define OD_FLAGS_LENGTH_4 (0x0000) /**< 4 byte and default */ +#define OD_FLAGS_LENGTH_8 (0x0080) /**< 8 byte */ +#define OD_FLAGS_LENGTH_CHAR (OD_FLAGS_LENGTH_1) /**< alias for OD_FLAGS_LENGTH_1 */ +#define OD_FLAGS_LENGTH_SHORT (0x0002) /**< sizeof(short) byte */ +#define OD_FLAGS_LENGTH_LONG (0x0004) /**< sizeof(long) byte */ +/** @} */ + +/** + * @brief Default value for parameter *width* of @ref od() + */ +#define OD_WIDTH_DEFAULT (16) + +/** + * @brief Dumps memory stored at *data* up to *data_len* in octal, decimal, or + * hexadecimal representation to stdout + * + * @param[in] data Data to dump. + * @param[in] data_len Length in bytes of *data* to output. + * @param[in] width Number of bytes per line. If *width* is 0, + * @ref OD_WIDTH_DEFAULT is assumed as a default value. + * @param[in] flags Flags as defined in @ref od_flags_address and + * @ref od_flags_bytes + */ +void od(void *data, size_t data_len, uint8_t width, uint16_t flags); + +/** + * @brief Dumps memory stored at *data* up to *data_len* in octal, decimal, or + * hexadecimal representation to stdout with + * `flags == OD_FLAGS_ADDRESS_HEX | OD_FLAGS_BYTES_HEX | OD_FLAGS_LENGTH_1`. + * + * @param[in] data Data to dump. + * @param[in] data_len Length in bytes of *data* to output. + * @param[in] width Number of bytes per line. If *width* is 0, + * @ref OD_WIDTH_DEFAULT is assumed as a default value. + */ +static inline void od_hex_dump(void *data, size_t data_len, uint8_t width) +{ + od(data, data_len, width, OD_FLAGS_ADDRESS_HEX | OD_FLAGS_BYTES_HEX | OD_FLAGS_LENGTH_1); +} + +#ifdef __cplusplus +} +#endif + +#endif /* __OD_H_ */ +/** @} */ diff --git a/sys/od/Makefile b/sys/od/Makefile new file mode 100644 index 000000000000..48422e909a47 --- /dev/null +++ b/sys/od/Makefile @@ -0,0 +1 @@ +include $(RIOTBASE)/Makefile.base diff --git a/sys/od/od.c b/sys/od/od.c new file mode 100644 index 000000000000..659ea3dff3e5 --- /dev/null +++ b/sys/od/od.c @@ -0,0 +1,336 @@ +/* + * Copyright (C) 2014 Martin Lenders + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @{ + * + * @file od.c + */ +#include +#include +#include + +#include "od.h" + +#define _OCTAL_BYTE_LENGTH (3) +#define _INT_BYTE_LENGTH (3) +#define _HEX_BYTE_LENGTH (2) + +static inline void _address_format(char *format, uint16_t flags) +{ + switch (flags & OD_FLAGS_ADDRESS_MASK) { + case OD_FLAGS_ADDRESS_OCTAL: + strncpy(format, "%09o", sizeof("%09o")); + break; + + case OD_FLAGS_ADDRESS_HEX: + strncpy(format, "%06x", sizeof("%06x")); + break; + + case OD_FLAGS_ADDRESS_DECIMAL: + strncpy(format, "%07d", sizeof("%07d")); + break; + + default: + break; + } +} + +static inline uint8_t _length(uint16_t flags) +{ + if (flags & OD_FLAGS_BYTES_CHAR) { + return 1; + } + + switch (flags & OD_FLAGS_LENGTH_MASK) { + case OD_FLAGS_LENGTH_1: + return 1; + + case OD_FLAGS_LENGTH_SHORT: + return sizeof(short); + + case OD_FLAGS_LENGTH_2: + return 2; + + case OD_FLAGS_LENGTH_LONG: + return sizeof(long); + + case OD_FLAGS_LENGTH_8: + return 8; + + case OD_FLAGS_LENGTH_4: + default: + return 4; + } +} + +static inline void _bytes_format(char *format, uint16_t flags) +{ + if (flags & OD_FLAGS_BYTES_CHAR) { + strncpy(format, " %c", sizeof(" %c")); + return; + } + + switch (flags & (OD_FLAGS_BYTES_MASK | OD_FLAGS_LENGTH_MASK)) { + case OD_FLAGS_BYTES_OCTAL | OD_FLAGS_LENGTH_1: + strncpy(format, " %03" PRIo8, sizeof(" %03" PRIo8)); + break; + + case OD_FLAGS_BYTES_OCTAL | OD_FLAGS_LENGTH_2: + strncpy(format, " %06" PRIo16, sizeof(" %06" PRIo16)); + break; + + case OD_FLAGS_BYTES_OCTAL | OD_FLAGS_LENGTH_4: + strncpy(format, " %012" PRIo32, sizeof(" %012" PRIo32)); + break; + + case OD_FLAGS_BYTES_OCTAL | OD_FLAGS_LENGTH_8: + strncpy(format, " %024" PRIo64, sizeof(" %024" PRIo64)); + break; + + case OD_FLAGS_BYTES_OCTAL | OD_FLAGS_LENGTH_SHORT: + sprintf(format, " %%0%dho", sizeof(short) * _OCTAL_BYTE_LENGTH); + break; + + case OD_FLAGS_BYTES_OCTAL | OD_FLAGS_LENGTH_LONG: + sprintf(format, " %%0%dlo", sizeof(long) * _OCTAL_BYTE_LENGTH); + break; + + case OD_FLAGS_BYTES_INT | OD_FLAGS_LENGTH_1: + strncpy(format, " %4" PRId8, sizeof(" %4" PRId8)); + break; + + case OD_FLAGS_BYTES_INT | OD_FLAGS_LENGTH_2: + strncpy(format, " %6" PRId16, sizeof(" %6" PRId16)); + break; + + case OD_FLAGS_BYTES_INT | OD_FLAGS_LENGTH_4: + strncpy(format, " %12" PRId32, sizeof(" %12" PRId32)); + break; + + case OD_FLAGS_BYTES_INT | OD_FLAGS_LENGTH_8: + strncpy(format, " %24" PRId64, sizeof(" %24" PRId64)); + break; + + case OD_FLAGS_BYTES_INT | OD_FLAGS_LENGTH_SHORT: + sprintf(format, " %%%dhd", sizeof(short) * _INT_BYTE_LENGTH); + break; + + case OD_FLAGS_BYTES_INT | OD_FLAGS_LENGTH_LONG: + sprintf(format, " %%%dld", sizeof(long) * _INT_BYTE_LENGTH); + break; + + case OD_FLAGS_BYTES_UINT | OD_FLAGS_LENGTH_1: + strncpy(format, " %3" PRIu8, sizeof(" %3" PRIu8)); + break; + + case OD_FLAGS_BYTES_UINT | OD_FLAGS_LENGTH_2: + strncpy(format, " %6" PRIu16, sizeof(" %6" PRIu16)); + break; + + case OD_FLAGS_BYTES_UINT | OD_FLAGS_LENGTH_4: + strncpy(format, " %12" PRIu32, sizeof(" %12" PRIu32)); + break; + + case OD_FLAGS_BYTES_UINT | OD_FLAGS_LENGTH_8: + strncpy(format, " %24" PRIu64, sizeof(" %24" PRIu64)); + break; + + case OD_FLAGS_BYTES_UINT | OD_FLAGS_LENGTH_SHORT: + sprintf(format, " %%%dhu", sizeof(short) * _INT_BYTE_LENGTH); + break; + + case OD_FLAGS_BYTES_UINT | OD_FLAGS_LENGTH_LONG: + sprintf(format, " %%%dlu", sizeof(long) * _INT_BYTE_LENGTH); + break; + + case OD_FLAGS_BYTES_HEX | OD_FLAGS_LENGTH_1: + strncpy(format, " %02" PRIx8, sizeof(" %02" PRIx8)); + break; + + case OD_FLAGS_BYTES_HEX | OD_FLAGS_LENGTH_2: + strncpy(format, " %04" PRIx16, sizeof(" %04" PRIx16)); + break; + + case OD_FLAGS_BYTES_HEX | OD_FLAGS_LENGTH_4: + strncpy(format, " %08" PRIx32, sizeof(" %08" PRIx32)); + break; + + case OD_FLAGS_BYTES_HEX | OD_FLAGS_LENGTH_8: + strncpy(format, " %016" PRIx64, sizeof(" %016" PRIx64)); + break; + + case OD_FLAGS_BYTES_HEX | OD_FLAGS_LENGTH_SHORT: + sprintf(format, " %%0%dhx", sizeof(short) * _HEX_BYTE_LENGTH); + break; + + case OD_FLAGS_BYTES_HEX | OD_FLAGS_LENGTH_LONG: + sprintf(format, " %%0%dlx", sizeof(long) * _HEX_BYTE_LENGTH); + break; + + default: + break; + } +} + +static void _print_date(void *data, size_t offset, char *format, uint8_t length, + uint16_t flags) +{ + switch (length) { + case 1: + if (flags & OD_FLAGS_BYTES_CHAR) { + switch (((char *)data)[offset]) { + case '\0': + printf(" \\0"); + return; + + case '\a': + printf(" \\a"); + return; + + case '\b': + printf(" \\b"); + return; + + case '\f': + printf(" \\f"); + return; + + case '\n': + printf(" \\n"); + return; + + case '\r': + printf(" \\r"); + return; + + case '\t': + printf(" \\t"); + return; + + case '\v': + printf(" \\v"); + return; + + default: + if (((char *)data)[offset] < 0) { + printf(" %03o", ((unsigned char *)data)[offset]); + return; + } + else if (((char *)data)[offset] < 32) { + printf(" %03o", ((char *)data)[offset]); + return; + } + + break; + } + + } + + if (flags & OD_FLAGS_BYTES_INT) { + printf(format, ((int8_t *)data)[offset]); + } + else { + printf(format, ((uint8_t *)data)[offset]); + } + + break; + + case 2: + if (flags & OD_FLAGS_BYTES_INT) { + printf(format, ((int16_t *)data)[offset]); + } + else { + printf(format, ((uint16_t *)data)[offset]); + } + + break; + + case 4: + default: + if (flags & OD_FLAGS_BYTES_INT) { + printf(format, ((int32_t *)data)[offset]); + } + else { + printf(format, ((uint32_t *)data)[offset]); + } + + break; + + case 8: + if (flags & OD_FLAGS_BYTES_INT) { + printf(format, ((int64_t *)data)[offset]); + } + else { + printf(format, ((uint64_t *)data)[offset]); + } + + break; + + } +} + +static int _log10(uint8_t a) +{ + int res = 0; + + while (a > 0) { + a /= 10; + ++res; + } + + return ++res; +} + +void od(void *data, size_t data_len, uint8_t width, uint16_t flags) +{ + char address_format[5]; + uint8_t date_length = _length(flags); + char bytes_format[_log10(date_length) + 7]; + + _address_format(address_format, flags); + _bytes_format(bytes_format, flags); + + if (width == 0) { + width = OD_WIDTH_DEFAULT; + } + + if (width < date_length) { + width = 1; + } + else { + width = (width / date_length); + } + + if (data_len % date_length) { + data_len = (data_len / date_length) + 1; + } + else { + data_len = data_len / date_length; + } + + if ((flags & OD_FLAGS_ADDRESS_MASK) != OD_FLAGS_ADDRESS_NONE) { + printf(address_format, 0); + } + + for (size_t i = 0; i < data_len; i++) { + _print_date(data, i, bytes_format, date_length, flags); + + if ((((i + 1) % width) == 0) || i == (data_len - 1)) { + printf("\n"); + + if (i != (data_len - 1)) { + if ((flags & OD_FLAGS_ADDRESS_MASK) != OD_FLAGS_ADDRESS_NONE) { + printf(address_format, date_length * (i + 1)); + } + } + } + } +} + +/** @} */