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