114fc1afb2
This patch makes hexdump return the number of bytes placed in the buffer excluding trailing NUL. In the case of overflow it returns the desired amount of bytes to produce the entire dump. Thus, it mimics snprintf(). This will be useful for users that would like to repeat with a bigger buffer. [akpm@linux-foundation.org: fix printk warning] Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
181 lines
4.0 KiB
C
181 lines
4.0 KiB
C
/*
|
|
* Test cases for lib/hexdump.c module.
|
|
*/
|
|
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
|
|
|
#include <linux/init.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/module.h>
|
|
#include <linux/random.h>
|
|
#include <linux/string.h>
|
|
|
|
static const unsigned char data_b[] = {
|
|
'\xbe', '\x32', '\xdb', '\x7b', '\x0a', '\x18', '\x93', '\xb2', /* 00 - 07 */
|
|
'\x70', '\xba', '\xc4', '\x24', '\x7d', '\x83', '\x34', '\x9b', /* 08 - 0f */
|
|
'\xa6', '\x9c', '\x31', '\xad', '\x9c', '\x0f', '\xac', '\xe9', /* 10 - 17 */
|
|
'\x4c', '\xd1', '\x19', '\x99', '\x43', '\xb1', '\xaf', '\x0c', /* 18 - 1f */
|
|
};
|
|
|
|
static const unsigned char data_a[] = ".2.{....p..$}.4...1.....L...C...";
|
|
|
|
static const char *test_data_1_le[] __initconst = {
|
|
"be", "32", "db", "7b", "0a", "18", "93", "b2",
|
|
"70", "ba", "c4", "24", "7d", "83", "34", "9b",
|
|
"a6", "9c", "31", "ad", "9c", "0f", "ac", "e9",
|
|
"4c", "d1", "19", "99", "43", "b1", "af", "0c",
|
|
};
|
|
|
|
static const char *test_data_2_le[] __initconst = {
|
|
"32be", "7bdb", "180a", "b293",
|
|
"ba70", "24c4", "837d", "9b34",
|
|
"9ca6", "ad31", "0f9c", "e9ac",
|
|
"d14c", "9919", "b143", "0caf",
|
|
};
|
|
|
|
static const char *test_data_4_le[] __initconst = {
|
|
"7bdb32be", "b293180a", "24c4ba70", "9b34837d",
|
|
"ad319ca6", "e9ac0f9c", "9919d14c", "0cafb143",
|
|
};
|
|
|
|
static const char *test_data_8_le[] __initconst = {
|
|
"b293180a7bdb32be", "9b34837d24c4ba70",
|
|
"e9ac0f9cad319ca6", "0cafb1439919d14c",
|
|
};
|
|
|
|
static void __init test_hexdump(size_t len, int rowsize, int groupsize,
|
|
bool ascii)
|
|
{
|
|
char test[32 * 3 + 2 + 32 + 1];
|
|
char real[32 * 3 + 2 + 32 + 1];
|
|
char *p;
|
|
const char **result;
|
|
size_t l = len;
|
|
int gs = groupsize, rs = rowsize;
|
|
unsigned int i;
|
|
|
|
hex_dump_to_buffer(data_b, l, rs, gs, real, sizeof(real), ascii);
|
|
|
|
if (rs != 16 && rs != 32)
|
|
rs = 16;
|
|
|
|
if (l > rs)
|
|
l = rs;
|
|
|
|
if (!is_power_of_2(gs) || gs > 8 || (len % gs != 0))
|
|
gs = 1;
|
|
|
|
if (gs == 8)
|
|
result = test_data_8_le;
|
|
else if (gs == 4)
|
|
result = test_data_4_le;
|
|
else if (gs == 2)
|
|
result = test_data_2_le;
|
|
else
|
|
result = test_data_1_le;
|
|
|
|
memset(test, ' ', sizeof(test));
|
|
|
|
/* hex dump */
|
|
p = test;
|
|
for (i = 0; i < l / gs; i++) {
|
|
const char *q = *result++;
|
|
size_t amount = strlen(q);
|
|
|
|
strncpy(p, q, amount);
|
|
p += amount + 1;
|
|
}
|
|
if (i)
|
|
p--;
|
|
|
|
/* ASCII part */
|
|
if (ascii) {
|
|
p = test + rs * 2 + rs / gs + 1;
|
|
strncpy(p, data_a, l);
|
|
p += l;
|
|
}
|
|
|
|
*p = '\0';
|
|
|
|
if (strcmp(test, real)) {
|
|
pr_err("Len: %zu row: %d group: %d\n", len, rowsize, groupsize);
|
|
pr_err("Result: '%s'\n", real);
|
|
pr_err("Expect: '%s'\n", test);
|
|
}
|
|
}
|
|
|
|
static void __init test_hexdump_set(int rowsize, bool ascii)
|
|
{
|
|
size_t d = min_t(size_t, sizeof(data_b), rowsize);
|
|
size_t len = get_random_int() % d + 1;
|
|
|
|
test_hexdump(len, rowsize, 4, ascii);
|
|
test_hexdump(len, rowsize, 2, ascii);
|
|
test_hexdump(len, rowsize, 8, ascii);
|
|
test_hexdump(len, rowsize, 1, ascii);
|
|
}
|
|
|
|
static void __init test_hexdump_overflow(bool ascii)
|
|
{
|
|
char buf[56];
|
|
const char *t = test_data_1_le[0];
|
|
size_t l = get_random_int() % sizeof(buf);
|
|
bool a;
|
|
int e, r;
|
|
|
|
memset(buf, ' ', sizeof(buf));
|
|
|
|
r = hex_dump_to_buffer(data_b, 1, 16, 1, buf, l, ascii);
|
|
|
|
if (ascii)
|
|
e = 50;
|
|
else
|
|
e = 2;
|
|
buf[e + 2] = '\0';
|
|
|
|
if (!l) {
|
|
a = r == e && buf[0] == ' ';
|
|
} else if (l < 3) {
|
|
a = r == e && buf[0] == '\0';
|
|
} else if (l < 4) {
|
|
a = r == e && !strcmp(buf, t);
|
|
} else if (ascii) {
|
|
if (l < 51)
|
|
a = r == e && buf[l - 1] == '\0' && buf[l - 2] == ' ';
|
|
else
|
|
a = r == e && buf[50] == '\0' && buf[49] == '.';
|
|
} else {
|
|
a = r == e && buf[e] == '\0';
|
|
}
|
|
|
|
if (!a) {
|
|
pr_err("Len: %zu rc: %u strlen: %zu\n", l, r, strlen(buf));
|
|
pr_err("Result: '%s'\n", buf);
|
|
}
|
|
}
|
|
|
|
static int __init test_hexdump_init(void)
|
|
{
|
|
unsigned int i;
|
|
int rowsize;
|
|
|
|
pr_info("Running tests...\n");
|
|
|
|
rowsize = (get_random_int() % 2 + 1) * 16;
|
|
for (i = 0; i < 16; i++)
|
|
test_hexdump_set(rowsize, false);
|
|
|
|
rowsize = (get_random_int() % 2 + 1) * 16;
|
|
for (i = 0; i < 16; i++)
|
|
test_hexdump_set(rowsize, true);
|
|
|
|
for (i = 0; i < 16; i++)
|
|
test_hexdump_overflow(false);
|
|
|
|
for (i = 0; i < 16; i++)
|
|
test_hexdump_overflow(true);
|
|
|
|
return -EINVAL;
|
|
}
|
|
module_init(test_hexdump_init);
|
|
MODULE_LICENSE("Dual BSD/GPL");
|