
4 changed files with 501 additions and 0 deletions
@ -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_ */ |
||||
/** @} */ |
@ -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)); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** @} */ |
Loading…
Reference in new issue