1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 * Copyright 2021 Oxide Computer Company
26 */
27
28 #include <netinet/in.h>
29 #include <limits.h>
30 #include <sys/types.h>
31 #include <sys/socket.h>
32
33 #include <mdb/mdb_string.h>
34 #include <mdb/mdb_modapi.h>
35 #include <mdb/mdb_lex.h>
36 #include <mdb/mdb_debug.h>
37 #include <mdb/mdb.h>
38
39 /*
40 * Convert the specified integer value to a string represented in the given
41 * base. The flags parameter is a bitfield of the formatting flags defined in
42 * mdb_string.h. A pointer to a static conversion buffer is returned.
43 */
44 const char *
numtostr(uintmax_t uvalue,int base,uint_t flags)45 numtostr(uintmax_t uvalue, int base, uint_t flags)
46 {
47 static const char ldigits[] = "0123456789abcdef";
48 static const char udigits[] = "0123456789ABCDEF";
49
50 static char buf[68]; /* Enough for ULLONG_MAX in binary plus prefixes */
51
52 const char *digits = (flags & NTOS_UPCASE) ? udigits : ldigits;
53 int i = sizeof (buf);
54
55 intmax_t value = (intmax_t)uvalue;
56 int neg = (flags & NTOS_UNSIGNED) == 0 && value < 0;
57 uintmax_t rem = neg ? -value : value;
58
59 buf[--i] = 0;
60
61 do {
62 buf[--i] = digits[rem % base];
63 rem /= base;
64 } while (rem != 0);
65
66 if (flags & NTOS_SHOWBASE) {
67 uintmax_t lim;
68 char c = 0;
69
70 switch (base) {
71 case 2:
72 lim = 1;
73 c = 'i';
74 break;
75 case 8:
76 lim = 7;
77 c = 'o';
78 break;
79 case 10:
80 lim = 9;
81 c = 't';
82 break;
83 case 16:
84 lim = 9;
85 c = 'x';
86 break;
87 }
88
89 if (c != 0 && uvalue > lim) {
90 buf[--i] = c;
91 buf[--i] = '0';
92 }
93 }
94
95 if (neg)
96 buf[--i] = '-';
97 else if (flags & NTOS_SIGNPOS)
98 buf[--i] = '+';
99
100 return ((const char *)(&buf[i]));
101 }
102
103 #define CTOI(x) (((x) >= '0' && (x) <= '9') ? (x) - '0' : \
104 ((x) >= 'a' && (x) <= 'z') ? (x) + 10 - 'a' : (x) + 10 - 'A')
105
106 /*
107 * Convert a string to an unsigned integer value using the specified base.
108 * In the event of overflow or an invalid character, we generate an
109 * error message and longjmp back to the main loop using yyerror().
110 */
111 uintmax_t
mdb_strtonum(const char * s,int base)112 mdb_strtonum(const char *s, int base)
113 {
114 uintmax_t multmax = (uintmax_t)ULLONG_MAX / (uintmax_t)(uint_t)base;
115 uintmax_t val = 0;
116 int c, i, neg = 0;
117
118 switch (c = *s) {
119 case '-':
120 neg++;
121 /*FALLTHRU*/
122 case '+':
123 c = *++s;
124 }
125
126 if (c == '\0')
127 goto done;
128
129 if ((val = CTOI(c)) >= base)
130 yyerror("digit '%c' is invalid in current base\n", c);
131
132 for (c = *++s; c != '\0'; c = *++s) {
133 if (val > multmax)
134 goto oflow;
135
136 if (c == '_')
137 continue;
138
139 if ((i = CTOI(c)) >= base)
140 yyerror("digit '%c' is invalid in current base\n", c);
141
142 val *= base;
143
144 if ((uintmax_t)ULLONG_MAX - val < (uintmax_t)i)
145 goto oflow;
146
147 val += i;
148 }
149 done:
150 return (neg ? -val : val);
151 oflow:
152 yyerror("specified value exceeds maximum immediate value\n");
153 return ((uintmax_t)ULLONG_MAX);
154 }
155
156 /*
157 * Quick string to unsigned long conversion function. This function performs
158 * no overflow checking and is only meant for internal mdb use. It allows
159 * the caller to specify the length of the string in bytes and a base.
160 */
161 ulong_t
strntoul(const char * s,size_t nbytes,int base)162 strntoul(const char *s, size_t nbytes, int base)
163 {
164 ulong_t n;
165 int c;
166
167 for (n = 0; nbytes != 0 && (c = *s) != '\0'; s++, nbytes--)
168 n = n * base + CTOI(c);
169
170 return (n);
171 }
172
173 /*
174 * Return a boolean value indicating whether or not a string consists
175 * solely of characters which are digits 0..9.
176 */
177 int
strisnum(const char * s)178 strisnum(const char *s)
179 {
180 for (; *s != '\0'; s++) {
181 if (*s < '0' || *s > '9')
182 return (0);
183 }
184
185 return (1);
186 }
187
188 /*
189 * Return a boolean value indicating whether or not a string contains a
190 * number. The number may be in the current radix, or it may have an
191 * explicit radix qualifier. The number will be validated against the
192 * legal characters for the given radix.
193 */
194 int
strisbasenum(const char * s)195 strisbasenum(const char *s)
196 {
197 char valid[] = "0123456789aAbBcCdDeEfF";
198 int radix = mdb.m_radix;
199
200 if (s[0] == '0') {
201 switch (s[1]) {
202 case 'I':
203 case 'i':
204 radix = 2;
205 s += 2;
206 break;
207 case 'O':
208 case 'o':
209 radix = 8;
210 s += 2;
211 break;
212 case 'T':
213 case 't':
214 radix = 10;
215 s += 2;
216 break;
217 case 'x':
218 case 'X':
219 radix = 16;
220 s += 2;
221 break;
222 }
223 }
224
225 /* limit `valid' to the digits valid for this base */
226 valid[radix > 10 ? 10 + (radix - 10) * 2 : radix] = '\0';
227
228 do {
229 if (!strchr(valid, *s))
230 return (0);
231 } while (*++s != '\0');
232
233 return (1);
234 }
235
236 /*
237 * Quick string to integer (base 10) conversion function. This performs
238 * no overflow checking and is only meant for internal mdb use.
239 */
240 int
strtoi(const char * s)241 strtoi(const char *s)
242 {
243 int c, n;
244
245 for (n = 0; (c = *s) >= '0' && c <= '9'; s++)
246 n = n * 10 + c - '0';
247
248 return (n);
249 }
250
251 /*
252 * Create a copy of string s using the mdb allocator interface.
253 */
254 char *
strdup(const char * s)255 strdup(const char *s)
256 {
257 char *s1 = mdb_alloc(strlen(s) + 1, UM_SLEEP);
258
259 (void) strcpy(s1, s);
260 return (s1);
261 }
262
263 /*
264 * Create a copy of string s, but only duplicate the first n bytes.
265 */
266 char *
strndup(const char * s,size_t n)267 strndup(const char *s, size_t n)
268 {
269 char *s2 = mdb_alloc(n + 1, UM_SLEEP);
270
271 (void) strncpy(s2, s, n);
272 s2[n] = '\0';
273 return (s2);
274 }
275
276 /*
277 * Convenience routine for freeing strings.
278 */
279 void
strfree(char * s)280 strfree(char *s)
281 {
282 mdb_free(s, strlen(s) + 1);
283 }
284
285 /*
286 * Transform string s inline, converting each embedded C escape sequence string
287 * to the corresponding character. For example, the substring "\n" is replaced
288 * by an inline '\n' character. The length of the resulting string is returned.
289 */
290 size_t
stresc2chr(char * s)291 stresc2chr(char *s)
292 {
293 char *p, *q, c;
294 int esc = 0;
295
296 for (p = q = s; (c = *p) != '\0'; p++) {
297 if (esc) {
298 switch (c) {
299 case '0':
300 case '1':
301 case '2':
302 case '3':
303 case '4':
304 case '5':
305 case '6':
306 case '7':
307 c -= '0';
308 p++;
309
310 if (*p >= '0' && *p <= '7') {
311 c = c * 8 + *p++ - '0';
312
313 if (*p >= '0' && *p <= '7')
314 c = c * 8 + *p - '0';
315 else
316 p--;
317 } else
318 p--;
319
320 *q++ = c;
321 break;
322
323 case 'a':
324 *q++ = '\a';
325 break;
326 case 'b':
327 *q++ = '\b';
328 break;
329 case 'f':
330 *q++ = '\f';
331 break;
332 case 'n':
333 *q++ = '\n';
334 break;
335 case 'r':
336 *q++ = '\r';
337 break;
338 case 't':
339 *q++ = '\t';
340 break;
341 case 'v':
342 *q++ = '\v';
343 break;
344 case '"':
345 case '\\':
346 *q++ = c;
347 break;
348 default:
349 *q++ = '\\';
350 *q++ = c;
351 }
352
353 esc = 0;
354
355 } else {
356 if ((esc = c == '\\') == 0)
357 *q++ = c;
358 }
359 }
360
361 *q = '\0';
362 return ((size_t)(q - s));
363 }
364
365 /*
366 * Create a copy of string s in which certain unprintable or special characters
367 * have been converted to the string representation of their C escape sequence.
368 * For example, the newline character is expanded to the string "\n".
369 */
370 char *
strchr2esc(const char * s,size_t n)371 strchr2esc(const char *s, size_t n)
372 {
373 const char *p;
374 char *q, *s2, c;
375 size_t addl = 0;
376
377 for (p = s; p < s + n; p++) {
378 switch (c = *p) {
379 case '\0':
380 case '\a':
381 case '\b':
382 case '\f':
383 case '\n':
384 case '\r':
385 case '\t':
386 case '\v':
387 case '"':
388 case '\\':
389 addl++; /* 1 add'l char needed to follow \ */
390 break;
391 case ' ':
392 break;
393 default:
394 if (c < '!' || c > '~')
395 addl += 3; /* 3 add'l chars following \ */
396 }
397 }
398
399 s2 = mdb_alloc(n + addl + 1, UM_SLEEP);
400
401 for (p = s, q = s2; p < s + n; p++) {
402 switch (c = *p) {
403 case '\0':
404 *q++ = '\\';
405 *q++ = '0';
406 break;
407 case '\a':
408 *q++ = '\\';
409 *q++ = 'a';
410 break;
411 case '\b':
412 *q++ = '\\';
413 *q++ = 'b';
414 break;
415 case '\f':
416 *q++ = '\\';
417 *q++ = 'f';
418 break;
419 case '\n':
420 *q++ = '\\';
421 *q++ = 'n';
422 break;
423 case '\r':
424 *q++ = '\\';
425 *q++ = 'r';
426 break;
427 case '\t':
428 *q++ = '\\';
429 *q++ = 't';
430 break;
431 case '\v':
432 *q++ = '\\';
433 *q++ = 'v';
434 break;
435 case '"':
436 *q++ = '\\';
437 *q++ = '"';
438 break;
439 case '\\':
440 *q++ = '\\';
441 *q++ = '\\';
442 break;
443 case ' ':
444 *q++ = c;
445 break;
446 default:
447 if (c < '!' || c > '~') {
448 *q++ = '\\';
449 *q++ = ((c >> 6) & 3) + '0';
450 *q++ = ((c >> 3) & 7) + '0';
451 *q++ = (c & 7) + '0';
452 } else
453 *q++ = c;
454 }
455 }
456
457 *q = '\0';
458 return (s2);
459 }
460
461 /*
462 * Create a copy of string s in which certain unprintable or special characters
463 * have been converted to an odd representation of their escape sequence.
464 * This algorithm is the old adb convention for representing such sequences.
465 */
466 char *
strchr2adb(const char * s,size_t n)467 strchr2adb(const char *s, size_t n)
468 {
469 size_t addl = 0;
470 const char *p;
471 char *q, *s2;
472
473 for (p = s; p < s + n; p++) {
474 char c = *p & CHAR_MAX;
475
476 if (c < ' ' || c == CHAR_MAX)
477 addl++; /* 1 add'l char needed for "^" */
478 }
479
480 s2 = mdb_alloc(n + addl + 1, UM_SLEEP);
481
482 for (p = s, q = s2; p < s + n; p++) {
483 char c = *p & CHAR_MAX;
484
485 if (c == CHAR_MAX) {
486 *q++ = '^';
487 *q++ = '?';
488 } else if (c < ' ') {
489 *q++ = '^';
490 *q++ = c + '@';
491 } else
492 *q++ = c;
493 }
494
495 *q = '\0';
496 return (s2);
497 }
498
499 /*
500 * Same as strchr, but we only search the first n characters
501 */
502 char *
strnchr(const char * s,int c,size_t n)503 strnchr(const char *s, int c, size_t n)
504 {
505 int i = 0;
506
507 for (i = 0; i < n; i++) {
508 if (*(s + i) == (char)c)
509 return ((char *)(s + i));
510 }
511
512 return (NULL);
513 }
514
515 /*
516 * Split the string s at the first occurrence of character c. This character
517 * is replaced by \0, and a pointer to the remainder of the string is returned.
518 */
519 char *
strsplit(char * s,char c)520 strsplit(char *s, char c)
521 {
522 char *p;
523
524 if ((p = strchr(s, c)) == NULL)
525 return (NULL);
526
527 *p++ = '\0';
528 return (p);
529 }
530
531 /*
532 * Same as strsplit, but split from the last occurrence of character c.
533 */
534 char *
strrsplit(char * s,char c)535 strrsplit(char *s, char c)
536 {
537 char *p;
538
539 if ((p = strrchr(s, c)) == NULL)
540 return (NULL);
541
542 *p++ = '\0';
543 return (p);
544 }
545
546 /*
547 * Return the address of the first occurrence of any character from s2
548 * in the string s1, or NULL if none exists. This is similar to libc's
549 * strpbrk, but we add a third parameter to limit the search to the
550 * specified number of bytes in s1, or a \0 character, whichever is
551 * encountered first.
552 */
553 const char *
strnpbrk(const char * s1,const char * s2,size_t nbytes)554 strnpbrk(const char *s1, const char *s2, size_t nbytes)
555 {
556 const char *p;
557
558 if (nbytes == 0)
559 return (NULL);
560
561 do {
562 for (p = s2; *p != '\0' && *p != *s1; p++)
563 continue;
564
565 if (*p != '\0')
566 return (s1);
567
568 } while (--nbytes != 0 && *s1++ != '\0');
569
570 return (NULL);
571 }
572
573 /*
574 * Abbreviate a string if it meets or exceeds the specified length, including
575 * the terminating null character. The string is abbreviated by replacing the
576 * last four characters with " ...". strabbr is useful in constructs such as
577 * this one, where nbytes = sizeof (buf):
578 *
579 * if (mdb_snprintf(buf, nbytes, "%s %d %c", ...) >= nbytes)
580 * (void) strabbr(buf, nbytes);
581 *
582 * No modifications are made if nbytes is too small to hold the suffix itself.
583 */
584 char *
strabbr(char * s,size_t nbytes)585 strabbr(char *s, size_t nbytes)
586 {
587 static const char suffix[] = " ...";
588
589 if (nbytes > sizeof (suffix) && strlen(s) >= nbytes - 1)
590 (void) strcpy(&s[nbytes - sizeof (suffix)], suffix);
591
592 return (s);
593 }
594
595 /*
596 * Return the basename (name after final /) of the given string. We use
597 * strbasename rather than basename to avoid conflicting with libgen.h's
598 * non-const function prototype.
599 */
600 const char *
strbasename(const char * s)601 strbasename(const char *s)
602 {
603 const char *p = strrchr(s, '/');
604
605 if (p == NULL)
606 return (s);
607
608 return (++p);
609 }
610
611 /*
612 * Return the directory name (name prior to the final /) of the given string.
613 * The string itself is modified.
614 */
615 char *
strdirname(char * s)616 strdirname(char *s)
617 {
618 static char slash[] = "/";
619 static char dot[] = ".";
620 char *p;
621
622 if (s == NULL || *s == '\0')
623 return (dot);
624
625 for (p = s + strlen(s); p != s && *--p == '/'; )
626 continue;
627
628 if (p == s && *p == '/')
629 return (slash);
630
631 while (p != s) {
632 if (*--p == '/') {
633 while (*p == '/' && p != s)
634 p--;
635 *++p = '\0';
636 return (s);
637 }
638 }
639
640 return (dot);
641 }
642
643 /*
644 * Return a pointer to the first character in the string that makes it an
645 * invalid identifer (i.e. incompatible with the mdb syntax), or NULL if
646 * the string is a valid identifier.
647 */
648 const char *
strbadid(const char * s)649 strbadid(const char *s)
650 {
651 return (strpbrk(s, "#%^&*-+=,:$/\\?<>;|!`'\"[]\n\t() {}"));
652 }
653
654 /*
655 * Return a boolean value indicating if the given string consists solely
656 * of printable ASCII characters terminated by \0.
657 */
658 int
strisprint(const char * s)659 strisprint(const char *s)
660 {
661 for (; *s != '\0'; s++) {
662 if (*s < ' ' || *s > '~')
663 return (0);
664 }
665
666 return (1);
667 }
668
669 /*
670 * This is a near direct copy of the inet_ntop() code in
671 * uts/common/inet/ip/ipv6.c, duplicated here for kmdb's sake.
672 */
673 static void
convert2ascii(char * buf,const in6_addr_t * addr)674 convert2ascii(char *buf, const in6_addr_t *addr)
675 {
676 int hexdigits;
677 int head_zero = 0;
678 int tail_zero = 0;
679 /* tempbuf must be big enough to hold ffff:\0 */
680 char tempbuf[6];
681 char *ptr;
682 uint16_t *addr_component, host_component;
683 size_t len;
684 int first = FALSE;
685 int med_zero = FALSE;
686 int end_zero = FALSE;
687
688 addr_component = (uint16_t *)addr;
689 ptr = buf;
690
691 /* First count if trailing zeroes higher in number */
692 for (hexdigits = 0; hexdigits < 8; hexdigits++) {
693 if (*addr_component == 0) {
694 if (hexdigits < 4)
695 head_zero++;
696 else
697 tail_zero++;
698 }
699 addr_component++;
700 }
701 addr_component = (uint16_t *)addr;
702 if (tail_zero > head_zero && (head_zero + tail_zero) != 7)
703 end_zero = TRUE;
704
705 for (hexdigits = 0; hexdigits < 8; hexdigits++) {
706 /* if entry is a 0 */
707 if (*addr_component == 0) {
708 if (!first && *(addr_component + 1) == 0) {
709 if (end_zero && (hexdigits < 4)) {
710 *ptr++ = '0';
711 *ptr++ = ':';
712 } else {
713 if (hexdigits == 0)
714 *ptr++ = ':';
715 /* add another */
716 *ptr++ = ':';
717 first = TRUE;
718 med_zero = TRUE;
719 }
720 } else if (first && med_zero) {
721 if (hexdigits == 7)
722 *ptr++ = ':';
723 addr_component++;
724 continue;
725 } else {
726 *ptr++ = '0';
727 *ptr++ = ':';
728 }
729 addr_component++;
730 continue;
731 }
732 if (med_zero)
733 med_zero = FALSE;
734
735 tempbuf[0] = '\0';
736 mdb_nhconvert(&host_component, addr_component,
737 sizeof (uint16_t));
738 (void) mdb_snprintf(tempbuf, sizeof (tempbuf), "%x:",
739 host_component & 0xffff);
740 len = strlen(tempbuf);
741 bcopy(tempbuf, ptr, len);
742 ptr = ptr + len;
743 addr_component++;
744 }
745 *--ptr = '\0';
746 }
747
748 char *
mdb_inet_ntop(int af,const void * addr,char * buf,size_t buflen)749 mdb_inet_ntop(int af, const void *addr, char *buf, size_t buflen)
750 {
751 in6_addr_t *v6addr;
752 uchar_t *v4addr;
753 char *caddr;
754
755 #define UC(b) (((int)b) & 0xff)
756 switch (af) {
757 case AF_INET:
758 ASSERT(buflen >= INET_ADDRSTRLEN);
759 v4addr = (uchar_t *)addr;
760 (void) mdb_snprintf(buf, buflen, "%d.%d.%d.%d",
761 UC(v4addr[0]), UC(v4addr[1]), UC(v4addr[2]), UC(v4addr[3]));
762 return (buf);
763
764 case AF_INET6:
765 ASSERT(buflen >= INET6_ADDRSTRLEN);
766 v6addr = (in6_addr_t *)addr;
767 if (IN6_IS_ADDR_V4MAPPED(v6addr)) {
768 caddr = (char *)addr;
769 (void) mdb_snprintf(buf, buflen, "::ffff:%d.%d.%d.%d",
770 UC(caddr[12]), UC(caddr[13]),
771 UC(caddr[14]), UC(caddr[15]));
772 } else if (IN6_IS_ADDR_V4COMPAT(v6addr)) {
773 caddr = (char *)addr;
774 (void) mdb_snprintf(buf, buflen, "::%d.%d.%d.%d",
775 UC(caddr[12]), UC(caddr[13]), UC(caddr[14]),
776 UC(caddr[15]));
777 } else if (IN6_IS_ADDR_UNSPECIFIED(v6addr)) {
778 (void) mdb_snprintf(buf, buflen, "::");
779 } else {
780 convert2ascii(buf, v6addr);
781 }
782 return (buf);
783 }
784 #undef UC
785
786 return (NULL);
787 }
788