1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

sys: Initial import of analytical object dump (od) module

This commit is contained in:
Martine Lenders 2014-10-27 19:03:04 +01:00
parent b7fc0df5d3
commit 3519a3d9be
4 changed files with 501 additions and 0 deletions

View File

@ -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

161
sys/include/od.h Normal file
View File

@ -0,0 +1,161 @@
/*
* Copyright (C) 2014 Martin Lenders <mlenders@inf.fu-berlin.de>
*
* 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
* <a href="http://pubs.opengroup.org/onlinepubs/9699919799/utilities/od.html">
* od
* </a> tool
*
* @see <a href="http://pubs.opengroup.org/onlinepubs/9699919799/utilities/od.html">
* od(1)
* </a>
* @{
*
* @file od.h
*
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
*/
#ifndef __OD_H_
#define __OD_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
/**
* @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_ */
/** @} */

1
sys/od/Makefile Normal file
View File

@ -0,0 +1 @@
include $(RIOTBASE)/Makefile.base

336
sys/od/od.c Normal file
View File

@ -0,0 +1,336 @@
/*
* Copyright (C) 2014 Martin Lenders <mlenders@inf.fu-berlin.de>
*
* 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 <stdio.h>
#include <string.h>
#include <inttypes.h>
#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));
}
}
}
}
}
/** @} */