1*43379a28SAndy Fiddaman /*
2*43379a28SAndy Fiddaman * This file and its contents are supplied under the terms of the
3*43379a28SAndy Fiddaman * Common Development and Distribution License ("CDDL"), version 1.0.
4*43379a28SAndy Fiddaman * You may only use this file in accordance with the terms of version
5*43379a28SAndy Fiddaman * 1.0 of the CDDL.
6*43379a28SAndy Fiddaman *
7*43379a28SAndy Fiddaman * A full copy of the text of the CDDL should have accompanied this
8*43379a28SAndy Fiddaman * source. A copy of the CDDL is also available via the Internet at
9*43379a28SAndy Fiddaman * http://www.illumos.org/license/CDDL.
10*43379a28SAndy Fiddaman */
11*43379a28SAndy Fiddaman
12*43379a28SAndy Fiddaman /*
13*43379a28SAndy Fiddaman * Copyright 2024 Oxide Computer Company
14*43379a28SAndy Fiddaman */
15*43379a28SAndy Fiddaman
16*43379a28SAndy Fiddaman /*
17*43379a28SAndy Fiddaman * Basic tests for the common hexdump routine.
18*43379a28SAndy Fiddaman */
19*43379a28SAndy Fiddaman
20*43379a28SAndy Fiddaman #include <err.h>
21*43379a28SAndy Fiddaman #include <errno.h>
22*43379a28SAndy Fiddaman #include <fcntl.h>
23*43379a28SAndy Fiddaman #include <stdio.h>
24*43379a28SAndy Fiddaman #include <stdlib.h>
25*43379a28SAndy Fiddaman #include <string.h>
26*43379a28SAndy Fiddaman #include <strings.h>
27*43379a28SAndy Fiddaman #include <unistd.h>
28*43379a28SAndy Fiddaman #include <sys/debug.h>
29*43379a28SAndy Fiddaman #include <sys/ilstr.h>
30*43379a28SAndy Fiddaman #include <sys/hexdump.h>
31*43379a28SAndy Fiddaman #include <sys/mman.h>
32*43379a28SAndy Fiddaman #include <sys/stat.h>
33*43379a28SAndy Fiddaman #include <sys/stdbool.h>
34*43379a28SAndy Fiddaman #include <sys/sysmacros.h>
35*43379a28SAndy Fiddaman #include <sys/types.h>
36*43379a28SAndy Fiddaman
37*43379a28SAndy Fiddaman #define DATADIR "/opt/os-tests/tests/hexdump/data"
38*43379a28SAndy Fiddaman
39*43379a28SAndy Fiddaman const char *
_umem_debug_init(void)40*43379a28SAndy Fiddaman _umem_debug_init(void)
41*43379a28SAndy Fiddaman {
42*43379a28SAndy Fiddaman return ("default,verbose");
43*43379a28SAndy Fiddaman }
44*43379a28SAndy Fiddaman
45*43379a28SAndy Fiddaman const char *
_umem_logging_init(void)46*43379a28SAndy Fiddaman _umem_logging_init(void)
47*43379a28SAndy Fiddaman {
48*43379a28SAndy Fiddaman return ("transaction,contents,fail");
49*43379a28SAndy Fiddaman }
50*43379a28SAndy Fiddaman
51*43379a28SAndy Fiddaman typedef struct test {
52*43379a28SAndy Fiddaman const char *name;
53*43379a28SAndy Fiddaman hexdump_flag_t flags;
54*43379a28SAndy Fiddaman uint8_t width;
55*43379a28SAndy Fiddaman uint8_t grouping;
56*43379a28SAndy Fiddaman uint64_t addr;
57*43379a28SAndy Fiddaman uint8_t indent;
58*43379a28SAndy Fiddaman uint8_t marker;
59*43379a28SAndy Fiddaman } test_t;
60*43379a28SAndy Fiddaman
61*43379a28SAndy Fiddaman test_t tests[] = {
62*43379a28SAndy Fiddaman {
63*43379a28SAndy Fiddaman .name = "basic",
64*43379a28SAndy Fiddaman }, {
65*43379a28SAndy Fiddaman .name = "header",
66*43379a28SAndy Fiddaman .flags = HDF_HEADER,
67*43379a28SAndy Fiddaman }, {
68*43379a28SAndy Fiddaman .name = "address",
69*43379a28SAndy Fiddaman .flags = HDF_ADDRESS,
70*43379a28SAndy Fiddaman }, {
71*43379a28SAndy Fiddaman .name = "ascii",
72*43379a28SAndy Fiddaman .flags = HDF_ASCII,
73*43379a28SAndy Fiddaman }, {
74*43379a28SAndy Fiddaman .name = "dedup",
75*43379a28SAndy Fiddaman .flags = HDF_DEDUP,
76*43379a28SAndy Fiddaman }, {
77*43379a28SAndy Fiddaman .name = "doublespace",
78*43379a28SAndy Fiddaman .flags = HDF_DOUBLESPACE,
79*43379a28SAndy Fiddaman }, {
80*43379a28SAndy Fiddaman .name = "address+header",
81*43379a28SAndy Fiddaman .flags = HDF_ADDRESS | HDF_HEADER,
82*43379a28SAndy Fiddaman }, {
83*43379a28SAndy Fiddaman .name = "default",
84*43379a28SAndy Fiddaman .flags = HDF_DEFAULT,
85*43379a28SAndy Fiddaman }, {
86*43379a28SAndy Fiddaman .name = "marker1",
87*43379a28SAndy Fiddaman .flags = HDF_DEFAULT | HDF_DEDUP,
88*43379a28SAndy Fiddaman .marker = 5
89*43379a28SAndy Fiddaman }, {
90*43379a28SAndy Fiddaman .name = "addr1",
91*43379a28SAndy Fiddaman .flags = HDF_DEFAULT | HDF_DEDUP,
92*43379a28SAndy Fiddaman .addr = 0x876543
93*43379a28SAndy Fiddaman }, {
94*43379a28SAndy Fiddaman .name = "addr2",
95*43379a28SAndy Fiddaman .flags = HDF_DEFAULT | HDF_DEDUP,
96*43379a28SAndy Fiddaman .addr = 0xffff8
97*43379a28SAndy Fiddaman }, {
98*43379a28SAndy Fiddaman .name = "align1",
99*43379a28SAndy Fiddaman .flags = HDF_DEFAULT | HDF_DEDUP | HDF_ALIGN,
100*43379a28SAndy Fiddaman .addr = 0x876543
101*43379a28SAndy Fiddaman }, {
102*43379a28SAndy Fiddaman .name = "indent",
103*43379a28SAndy Fiddaman .flags = HDF_DEFAULT | HDF_DEDUP,
104*43379a28SAndy Fiddaman .indent = 3
105*43379a28SAndy Fiddaman }, {
106*43379a28SAndy Fiddaman .name = "group2",
107*43379a28SAndy Fiddaman .flags = HDF_DEFAULT | HDF_DEDUP,
108*43379a28SAndy Fiddaman .addr = 0x876543,
109*43379a28SAndy Fiddaman .grouping = 2,
110*43379a28SAndy Fiddaman }, {
111*43379a28SAndy Fiddaman .name = "group4",
112*43379a28SAndy Fiddaman .flags = HDF_DEFAULT | HDF_DEDUP,
113*43379a28SAndy Fiddaman .addr = 0x876543,
114*43379a28SAndy Fiddaman .grouping = 4,
115*43379a28SAndy Fiddaman }, {
116*43379a28SAndy Fiddaman .name = "group8",
117*43379a28SAndy Fiddaman .flags = HDF_DEFAULT | HDF_DEDUP,
118*43379a28SAndy Fiddaman .addr = 0x876543,
119*43379a28SAndy Fiddaman .grouping = 8,
120*43379a28SAndy Fiddaman }, {
121*43379a28SAndy Fiddaman .name = "width12",
122*43379a28SAndy Fiddaman .flags = HDF_DEFAULT | HDF_DEDUP,
123*43379a28SAndy Fiddaman .addr = 0x876543,
124*43379a28SAndy Fiddaman .width = 12,
125*43379a28SAndy Fiddaman .grouping = 4
126*43379a28SAndy Fiddaman }, {
127*43379a28SAndy Fiddaman .name = "wide1",
128*43379a28SAndy Fiddaman .flags = HDF_ADDRESS | HDF_HEADER,
129*43379a28SAndy Fiddaman .addr = 0x876543,
130*43379a28SAndy Fiddaman .width = 32,
131*43379a28SAndy Fiddaman .grouping = 8
132*43379a28SAndy Fiddaman }, {
133*43379a28SAndy Fiddaman .name = "narrow1",
134*43379a28SAndy Fiddaman .flags = HDF_DEFAULT | HDF_DOUBLESPACE,
135*43379a28SAndy Fiddaman .addr = 0x876543,
136*43379a28SAndy Fiddaman .width = 4,
137*43379a28SAndy Fiddaman .grouping = 2
138*43379a28SAndy Fiddaman }, {
139*43379a28SAndy Fiddaman .name = "narrow2",
140*43379a28SAndy Fiddaman .flags = HDF_DEFAULT | HDF_DEDUP,
141*43379a28SAndy Fiddaman .addr = 0x876543,
142*43379a28SAndy Fiddaman .width = 1,
143*43379a28SAndy Fiddaman .grouping = 1
144*43379a28SAndy Fiddaman }
145*43379a28SAndy Fiddaman };
146*43379a28SAndy Fiddaman
147*43379a28SAndy Fiddaman static char *flagdescr[] = {
148*43379a28SAndy Fiddaman "HEADER",
149*43379a28SAndy Fiddaman "ADDRESS",
150*43379a28SAndy Fiddaman "ASCII",
151*43379a28SAndy Fiddaman "ALIGN",
152*43379a28SAndy Fiddaman "DEDUP",
153*43379a28SAndy Fiddaman "DOUBLESPACE",
154*43379a28SAndy Fiddaman };
155*43379a28SAndy Fiddaman
156*43379a28SAndy Fiddaman static void
descr(test_t * t,ilstr_t * i)157*43379a28SAndy Fiddaman descr(test_t *t, ilstr_t *i)
158*43379a28SAndy Fiddaman {
159*43379a28SAndy Fiddaman ilstr_append_str(i, "=============================================\n");
160*43379a28SAndy Fiddaman ilstr_aprintf(i, "[%s] w=%u g=%u a=0x%x - ",
161*43379a28SAndy Fiddaman t->name, t->width, t->grouping, t->addr);
162*43379a28SAndy Fiddaman
163*43379a28SAndy Fiddaman int flags = t->flags;
164*43379a28SAndy Fiddaman bool first = true;
165*43379a28SAndy Fiddaman while (flags != 0) {
166*43379a28SAndy Fiddaman int b = fls(flags);
167*43379a28SAndy Fiddaman if (b == 0)
168*43379a28SAndy Fiddaman break;
169*43379a28SAndy Fiddaman b--;
170*43379a28SAndy Fiddaman VERIFY3S(b, <, ARRAY_SIZE(flagdescr));
171*43379a28SAndy Fiddaman if (first)
172*43379a28SAndy Fiddaman first = false;
173*43379a28SAndy Fiddaman else
174*43379a28SAndy Fiddaman ilstr_append_char(i, ' ');
175*43379a28SAndy Fiddaman ilstr_aprintf(i, "%s", flagdescr[b]);
176*43379a28SAndy Fiddaman flags &= ~(1<< b);
177*43379a28SAndy Fiddaman }
178*43379a28SAndy Fiddaman ilstr_append_char(i, '\n');
179*43379a28SAndy Fiddaman ilstr_append_str(i, "=============================================\n");
180*43379a28SAndy Fiddaman }
181*43379a28SAndy Fiddaman
182*43379a28SAndy Fiddaman static int
cb(void * arg,uint64_t addr __unused,const char * str,size_t l)183*43379a28SAndy Fiddaman cb(void *arg, uint64_t addr __unused, const char *str, size_t l)
184*43379a28SAndy Fiddaman {
185*43379a28SAndy Fiddaman ilstr_t *i = arg;
186*43379a28SAndy Fiddaman
187*43379a28SAndy Fiddaman ilstr_append_str(i, str);
188*43379a28SAndy Fiddaman ilstr_append_char(i, '\n');
189*43379a28SAndy Fiddaman
190*43379a28SAndy Fiddaman return (0);
191*43379a28SAndy Fiddaman }
192*43379a28SAndy Fiddaman
193*43379a28SAndy Fiddaman static void
run(test_t * t,uint8_t * data,size_t len,ilstr_t * i)194*43379a28SAndy Fiddaman run(test_t *t, uint8_t *data, size_t len, ilstr_t *i)
195*43379a28SAndy Fiddaman {
196*43379a28SAndy Fiddaman hexdump_t hd;
197*43379a28SAndy Fiddaman
198*43379a28SAndy Fiddaman descr(t, i);
199*43379a28SAndy Fiddaman
200*43379a28SAndy Fiddaman hexdump_init(&hd);
201*43379a28SAndy Fiddaman if (t->width != 0)
202*43379a28SAndy Fiddaman hexdump_set_width(&hd, t->width);
203*43379a28SAndy Fiddaman if (t->grouping != 0)
204*43379a28SAndy Fiddaman hexdump_set_grouping(&hd, t->grouping);
205*43379a28SAndy Fiddaman if (t->addr != 0)
206*43379a28SAndy Fiddaman hexdump_set_addr(&hd, t->addr);
207*43379a28SAndy Fiddaman if (t->indent != 0)
208*43379a28SAndy Fiddaman hexdump_set_indent(&hd, t->indent);
209*43379a28SAndy Fiddaman if (t->marker != 0)
210*43379a28SAndy Fiddaman hexdump_set_marker(&hd, t->marker);
211*43379a28SAndy Fiddaman
212*43379a28SAndy Fiddaman VERIFY0(hexdumph(&hd, data, len, t->flags, cb, (void *)i));
213*43379a28SAndy Fiddaman
214*43379a28SAndy Fiddaman hexdump_fini(&hd);
215*43379a28SAndy Fiddaman
216*43379a28SAndy Fiddaman VERIFY3U(ilstr_errno(i), ==, ILSTR_ERROR_OK);
217*43379a28SAndy Fiddaman }
218*43379a28SAndy Fiddaman
219*43379a28SAndy Fiddaman static uint8_t *
mapfile(const char * filename,size_t * lenp)220*43379a28SAndy Fiddaman mapfile(const char *filename, size_t *lenp)
221*43379a28SAndy Fiddaman {
222*43379a28SAndy Fiddaman uint8_t *p;
223*43379a28SAndy Fiddaman struct stat st;
224*43379a28SAndy Fiddaman int fd;
225*43379a28SAndy Fiddaman
226*43379a28SAndy Fiddaman if ((fd = open(filename, O_RDONLY)) == -1)
227*43379a28SAndy Fiddaman err(EXIT_FAILURE, "could not open '%s'", filename);
228*43379a28SAndy Fiddaman
229*43379a28SAndy Fiddaman if (fstat(fd, &st) == -1)
230*43379a28SAndy Fiddaman err(EXIT_FAILURE, "failed to stat '%s'", filename);
231*43379a28SAndy Fiddaman
232*43379a28SAndy Fiddaman p = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
233*43379a28SAndy Fiddaman if (p == MAP_FAILED)
234*43379a28SAndy Fiddaman err(EXIT_FAILURE, "failed to mmap 0x%lx bytes from '%s'",
235*43379a28SAndy Fiddaman st.st_size, filename);
236*43379a28SAndy Fiddaman
237*43379a28SAndy Fiddaman VERIFY0(close(fd));
238*43379a28SAndy Fiddaman
239*43379a28SAndy Fiddaman *lenp = st.st_size;
240*43379a28SAndy Fiddaman return (p);
241*43379a28SAndy Fiddaman }
242*43379a28SAndy Fiddaman
243*43379a28SAndy Fiddaman static void __PRINTFLIKE(2) __NORETURN
usage(int ec,const char * fmt,...)244*43379a28SAndy Fiddaman usage(int ec, const char *fmt, ...)
245*43379a28SAndy Fiddaman {
246*43379a28SAndy Fiddaman va_list ap;
247*43379a28SAndy Fiddaman
248*43379a28SAndy Fiddaman if (fmt != NULL) {
249*43379a28SAndy Fiddaman va_start(ap, fmt);
250*43379a28SAndy Fiddaman (void) vfprintf(stderr, fmt, ap);
251*43379a28SAndy Fiddaman va_end(ap);
252*43379a28SAndy Fiddaman (void) fprintf(stderr, "\n");
253*43379a28SAndy Fiddaman }
254*43379a28SAndy Fiddaman
255*43379a28SAndy Fiddaman (void) fprintf(stderr,
256*43379a28SAndy Fiddaman "Usage:\n"
257*43379a28SAndy Fiddaman " -d <directory> specify data directory\n"
258*43379a28SAndy Fiddaman " (default: %s)\n"
259*43379a28SAndy Fiddaman " -g generate baseline files\n"
260*43379a28SAndy Fiddaman " -h show usage\n"
261*43379a28SAndy Fiddaman " -t <test> run just the test named <test>\n"
262*43379a28SAndy Fiddaman " -v send test output to stdout\n",
263*43379a28SAndy Fiddaman DATADIR);
264*43379a28SAndy Fiddaman exit(ec);
265*43379a28SAndy Fiddaman }
266*43379a28SAndy Fiddaman
267*43379a28SAndy Fiddaman int
main(int argc,char ** argv)268*43379a28SAndy Fiddaman main(int argc, char **argv)
269*43379a28SAndy Fiddaman {
270*43379a28SAndy Fiddaman uint8_t *data;
271*43379a28SAndy Fiddaman const char *datadir = DATADIR;
272*43379a28SAndy Fiddaman char buf[MAXPATHLEN + 1];
273*43379a28SAndy Fiddaman const char *test = NULL;
274*43379a28SAndy Fiddaman ilstr_t testout;
275*43379a28SAndy Fiddaman uint_t failures = 0;
276*43379a28SAndy Fiddaman size_t maplen;
277*43379a28SAndy Fiddaman int c;
278*43379a28SAndy Fiddaman
279*43379a28SAndy Fiddaman enum {
280*43379a28SAndy Fiddaman MODE_TEST,
281*43379a28SAndy Fiddaman MODE_GENERATE,
282*43379a28SAndy Fiddaman MODE_DUMP
283*43379a28SAndy Fiddaman } testmode = MODE_TEST;
284*43379a28SAndy Fiddaman
285*43379a28SAndy Fiddaman while ((c = getopt(argc, argv, ":d:ght:v")) != -1) {
286*43379a28SAndy Fiddaman switch (c) {
287*43379a28SAndy Fiddaman case 'd':
288*43379a28SAndy Fiddaman datadir = optarg;
289*43379a28SAndy Fiddaman break;
290*43379a28SAndy Fiddaman case 'g':
291*43379a28SAndy Fiddaman testmode = MODE_GENERATE;
292*43379a28SAndy Fiddaman break;
293*43379a28SAndy Fiddaman case 'h':
294*43379a28SAndy Fiddaman usage(0, NULL);
295*43379a28SAndy Fiddaman case 't':
296*43379a28SAndy Fiddaman test = optarg;
297*43379a28SAndy Fiddaman break;
298*43379a28SAndy Fiddaman case 'v':
299*43379a28SAndy Fiddaman testmode = MODE_DUMP;
300*43379a28SAndy Fiddaman break;
301*43379a28SAndy Fiddaman case ':':
302*43379a28SAndy Fiddaman usage(EXIT_FAILURE,
303*43379a28SAndy Fiddaman "Option -%c requires an operand\n", optopt);
304*43379a28SAndy Fiddaman case '?':
305*43379a28SAndy Fiddaman usage(EXIT_FAILURE, "Unknown option: -%c", optopt);
306*43379a28SAndy Fiddaman }
307*43379a28SAndy Fiddaman }
308*43379a28SAndy Fiddaman
309*43379a28SAndy Fiddaman if (snprintf(buf, sizeof (buf), "%s/_input", datadir) >= sizeof (buf))
310*43379a28SAndy Fiddaman errx(EXIT_FAILURE, "Overflow building data dir path");
311*43379a28SAndy Fiddaman
312*43379a28SAndy Fiddaman data = mapfile(buf, &maplen);
313*43379a28SAndy Fiddaman
314*43379a28SAndy Fiddaman ilstr_init(&testout, 0);
315*43379a28SAndy Fiddaman
316*43379a28SAndy Fiddaman for (size_t i = 0; i < ARRAY_SIZE(tests); i++) {
317*43379a28SAndy Fiddaman if (test != NULL && strcmp(test, tests[i].name) != 0)
318*43379a28SAndy Fiddaman continue;
319*43379a28SAndy Fiddaman
320*43379a28SAndy Fiddaman if (snprintf(buf, sizeof (buf), "%s/%s", datadir,
321*43379a28SAndy Fiddaman tests[i].name) >= sizeof (buf)) {
322*43379a28SAndy Fiddaman errx(EXIT_FAILURE, "Overflow building output path");
323*43379a28SAndy Fiddaman }
324*43379a28SAndy Fiddaman
325*43379a28SAndy Fiddaman run(&tests[i], data, maplen, &testout);
326*43379a28SAndy Fiddaman
327*43379a28SAndy Fiddaman switch (testmode) {
328*43379a28SAndy Fiddaman case MODE_TEST: {
329*43379a28SAndy Fiddaman uint8_t *refdata;
330*43379a28SAndy Fiddaman size_t reflen;
331*43379a28SAndy Fiddaman
332*43379a28SAndy Fiddaman refdata = mapfile(buf, &reflen);
333*43379a28SAndy Fiddaman
334*43379a28SAndy Fiddaman if (ilstr_len(&testout) != reflen ||
335*43379a28SAndy Fiddaman memcmp(ilstr_cstr(&testout), refdata,
336*43379a28SAndy Fiddaman reflen) != 0) {
337*43379a28SAndy Fiddaman failures++;
338*43379a28SAndy Fiddaman (void) fprintf(stderr,
339*43379a28SAndy Fiddaman "Hexdump '%s' output mismatch",
340*43379a28SAndy Fiddaman tests[i].name);
341*43379a28SAndy Fiddaman (void) fprintf(stderr, "== Expected:\n%s\n",
342*43379a28SAndy Fiddaman refdata);
343*43379a28SAndy Fiddaman (void) fprintf(stderr, "== Got:\n%s\n",
344*43379a28SAndy Fiddaman ilstr_cstr(&testout));
345*43379a28SAndy Fiddaman }
346*43379a28SAndy Fiddaman
347*43379a28SAndy Fiddaman VERIFY0(munmap(refdata, reflen));
348*43379a28SAndy Fiddaman break;
349*43379a28SAndy Fiddaman }
350*43379a28SAndy Fiddaman case MODE_GENERATE: {
351*43379a28SAndy Fiddaman FILE *fp;
352*43379a28SAndy Fiddaman
353*43379a28SAndy Fiddaman fp = fopen(buf, "w");
354*43379a28SAndy Fiddaman if (fp == NULL)
355*43379a28SAndy Fiddaman err(EXIT_FAILURE, "Failed to create %s", buf);
356*43379a28SAndy Fiddaman (void) fprintf(fp, "%s", ilstr_cstr(&testout));
357*43379a28SAndy Fiddaman VERIFY0(fclose(fp));
358*43379a28SAndy Fiddaman break;
359*43379a28SAndy Fiddaman }
360*43379a28SAndy Fiddaman case MODE_DUMP:
361*43379a28SAndy Fiddaman (void) fprintf(stdout, "%s\n", ilstr_cstr(&testout));
362*43379a28SAndy Fiddaman break;
363*43379a28SAndy Fiddaman }
364*43379a28SAndy Fiddaman ilstr_reset(&testout);
365*43379a28SAndy Fiddaman }
366*43379a28SAndy Fiddaman
367*43379a28SAndy Fiddaman ilstr_fini(&testout);
368*43379a28SAndy Fiddaman
369*43379a28SAndy Fiddaman VERIFY0(munmap(data, maplen));
370*43379a28SAndy Fiddaman
371*43379a28SAndy Fiddaman if (testmode == MODE_TEST && failures == 0)
372*43379a28SAndy Fiddaman (void) printf("All hexdump tests have passed.\n");
373*43379a28SAndy Fiddaman
374*43379a28SAndy Fiddaman return (failures > 0 ? EXIT_FAILURE : 0);
375*43379a28SAndy Fiddaman }
376