xref: /illumos-gate/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_pmap.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
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 (c) 1991, 1999 by Sun Microsystems, Inc.
24  * All rights reserved.
25  */
26 
27 #ident	"%Z%%M%	%I%	%E% SMI"	/* SunOS	*/
28 
29 #include <sys/types.h>
30 #include <sys/errno.h>
31 #include <setjmp.h>
32 #include <sys/tiuser.h>
33 #include <string.h>
34 
35 #include <rpc/types.h>
36 #include <rpc/xdr.h>
37 #include <rpc/auth.h>
38 #include <rpc/clnt.h>
39 #include <rpc/rpc_msg.h>
40 #include <rpc/pmap_prot.h>
41 #include "snoop.h"
42 
43 /*
44  * Number of bytes to display from a string (address, netid, etc.).
45  */
46 #define	MAXSTRINGLEN	64
47 
48 extern char *dlc_header;
49 extern jmp_buf xdr_err;
50 
51 static void interpret_pmap_2(int, int, int, int, int, char *, int);
52 static void interpret_pmap_4(int, int, int, int, int, char *, int);
53 static void stash_callit(ulong_t, int, int, int, int);
54 
55 void
56 interpret_pmap(flags, type, xid, vers, proc, data, len)
57 	int flags, type, xid, vers, proc;
58 	char *data;
59 	int len;
60 {
61 	switch (vers) {
62 	case 2:	interpret_pmap_2(flags, type, xid, vers, proc, data, len);
63 		break;
64 
65 	/* Version 3 is a subset of version 4 */
66 	case 3:
67 	case 4:	interpret_pmap_4(flags, type, xid, vers, proc, data, len);
68 		break;
69 	}
70 }
71 
72 void show_pmap();
73 char *sum_pmaplist();
74 void show_pmaplist();
75 
76 static char *procnames_short_2[] = {
77 	"Null",		/* 0 */
78 	"SET",		/* 1 */
79 	"UNSET",	/* 2 */
80 	"GETPORT",	/* 3 */
81 	"DUMP",		/* 4 */
82 	"CALLIT",	/* 5 */
83 };
84 
85 static char *procnames_long_2[] = {
86 	"Null procedure",	/* 0 */
87 	"Set port",		/* 1 */
88 	"Unset port",		/* 2 */
89 	"Get port number",	/* 3 */
90 	"Dump the mappings",	/* 4 */
91 	"Indirect call",	/* 5 */
92 };
93 
94 #define	MAXPROC_2	5
95 
96 void
97 interpret_pmap_2(flags, type, xid, vers, proc, data, len)
98 	int flags, type, xid, vers, proc;
99 	char *data;
100 	int len;
101 {
102 	char *line;
103 	unsigned port, proto;
104 	unsigned iprog, ivers, iproc, ilen;
105 	extern int pi_frame;
106 	struct cache_struct *x, *find_callit();
107 	int trailer_done = 0;
108 
109 	if (proc < 0 || proc > MAXPROC_2)
110 		return;
111 
112 	if (proc == PMAPPROC_CALLIT) {
113 		if (type == CALL) {
114 			iprog = getxdr_u_long();
115 			ivers = getxdr_u_long();
116 			iproc = getxdr_u_long();
117 			stash_callit(xid, pi_frame,
118 				iprog, ivers, iproc);
119 		} else {
120 			x = find_callit(xid);
121 		}
122 	}
123 
124 	if (flags & F_SUM) {
125 		if (setjmp(xdr_err)) {
126 			return;
127 		}
128 
129 		line = get_sum_line();
130 
131 		if (type == CALL) {
132 			(void) sprintf(line,
133 				"PORTMAP C %s",
134 				procnames_short_2[proc]);
135 			line += strlen(line);
136 			switch (proc) {
137 			case PMAPPROC_GETPORT:
138 				iprog = getxdr_u_long();
139 				ivers = getxdr_u_long();
140 				proto = getxdr_u_long();
141 				(void) sprintf(line,
142 					" prog=%d (%s) vers=%d proto=%s",
143 					iprog, nameof_prog(iprog),
144 					ivers,
145 					getproto(proto));
146 				break;
147 			case PMAPPROC_CALLIT:
148 				(void) getxdr_u_long(); /* length */
149 				(void) sprintf(line,
150 					" prog=%s vers=%d proc=%d",
151 					nameof_prog(iprog),
152 					ivers, iproc);
153 				data += 16; /* prog+ver+proc+len */
154 				len -= 16;
155 				protoprint(flags, type, xid,
156 					iprog, ivers, iproc,
157 					data, len);
158 				break;
159 			default:
160 				break;
161 			}
162 			check_retransmit(line, xid);
163 		} else {
164 			(void) sprintf(line, "PORTMAP R %s ",
165 				procnames_short_2[proc]);
166 			line += strlen(line);
167 			switch (proc) {
168 			case PMAPPROC_GETPORT:
169 				port = getxdr_u_long();
170 				(void) sprintf(line, "port=%d",
171 					port);
172 				break;
173 			case PMAPPROC_DUMP:
174 				(void) sprintf(line, "%s",
175 					sum_pmaplist());
176 				break;
177 			case PMAPPROC_CALLIT:
178 				port = getxdr_u_long();
179 				ilen = getxdr_u_long();
180 				(void) sprintf(line, "port=%d len=%d",
181 					port, ilen);
182 				if (x != NULL) {
183 					protoprint(flags, type, xid,
184 						x->xid_prog,
185 						x->xid_vers,
186 						x->xid_proc,
187 						data, len);
188 				}
189 				break;
190 			default:
191 				break;
192 			}
193 		}
194 	}
195 
196 	if (flags & F_DTAIL) {
197 		show_header("PMAP:  ", "Portmapper", len);
198 		show_space();
199 		if (setjmp(xdr_err)) {
200 			return;
201 		}
202 		(void) sprintf(get_line(0, 0),
203 			"Proc = %d (%s)",
204 			proc, procnames_long_2[proc]);
205 		if (type == CALL) {
206 			switch (proc) {
207 			case PMAPPROC_NULL:
208 			case PMAPPROC_SET:
209 			case PMAPPROC_UNSET:
210 				break;
211 			case PMAPPROC_GETPORT:
212 				iprog = getxdr_u_long();
213 				(void) sprintf(get_line(0, 0),
214 					"Program = %d (%s)",
215 					iprog, nameof_prog(iprog));
216 				(void) showxdr_u_long("Version = %d");
217 				proto = getxdr_u_long();
218 				(void) sprintf(get_line(0, 0),
219 					"Protocol = %d (%s)",
220 					proto, getproto(proto));
221 				break;
222 			case PMAPPROC_DUMP:
223 				break;
224 			case PMAPPROC_CALLIT:
225 				(void) sprintf(get_line(0, 0),
226 					"Program = %d (%s)",
227 					iprog, nameof_prog(iprog));
228 				(void) sprintf(get_line(0, 0),
229 					"Version = %d", ivers);
230 				(void) sprintf(get_line(0, 0),
231 					"Proc    = %d", iproc);
232 				(void) showxdr_u_long(
233 					"Callit data = %d bytes");
234 				show_trailer();
235 				trailer_done = 1;
236 				data += 16; /* prog+ver+proc+len */
237 				len -= 16;
238 				protoprint(flags, type, xid,
239 					iprog, ivers, iproc,
240 					data, len);
241 				break;
242 			}
243 		} else {
244 			switch (proc) {
245 			case PMAPPROC_NULL:
246 			case PMAPPROC_SET:
247 			case PMAPPROC_UNSET:
248 				break;
249 			case PMAPPROC_GETPORT:
250 				(void) showxdr_u_long("Port = %d");
251 				break;
252 			case PMAPPROC_DUMP:
253 				show_pmaplist();
254 				break;
255 			case PMAPPROC_CALLIT:
256 				(void) showxdr_u_long("Port = %d");
257 				(void) showxdr_u_long("Length = %d bytes");
258 				show_trailer();
259 				trailer_done = 1;
260 				if (x != NULL) {
261 					protoprint(flags, type, xid,
262 						x->xid_prog,
263 						x->xid_vers,
264 						x->xid_proc,
265 						data, len);
266 				}
267 				break;
268 			}
269 		}
270 		if (!trailer_done)
271 			show_trailer();
272 	}
273 }
274 
275 char *
276 sum_pmaplist()
277 {
278 	int maps = 0;
279 	static char buff[16];
280 
281 	if (setjmp(xdr_err)) {
282 		(void) sprintf(buff, "%d+ map(s) found", maps);
283 		return (buff);
284 	}
285 
286 	while (getxdr_u_long()) {
287 		(void) getxdr_u_long();	/* program */
288 		(void) getxdr_u_long();	/* version */
289 		(void) getxdr_u_long();	/* protocol */
290 		(void) getxdr_u_long();	/* port */
291 		maps++;
292 	}
293 
294 	(void) sprintf(buff, "%d map(s) found", maps);
295 	return (buff);
296 }
297 
298 void
299 show_pmaplist()
300 {
301 	unsigned prog, vers, proto, port;
302 	int maps = 0;
303 
304 	if (setjmp(xdr_err)) {
305 		(void) sprintf(get_line(0, 0),
306 			" %d+ maps. (Frame is incomplete)",
307 			maps);
308 		return;
309 	}
310 
311 	(void) sprintf(get_line(0, 0),
312 		" Program Version Protocol   Port");
313 
314 	while (getxdr_u_long()) {
315 		prog  = getxdr_u_long();
316 		vers  = getxdr_u_long();
317 		proto = getxdr_u_long();
318 		port  = getxdr_u_long();
319 		(void) sprintf(get_line(0, 0),
320 			"%8d%8d%9d%7d  %s",
321 			prog, vers, proto, port, nameof_prog(prog));
322 		maps++;
323 	}
324 
325 	(void) sprintf(get_line(0, 0), " %d maps", maps);
326 }
327 
328 /*
329  * ******************************************
330  */
331 char *sum_rpcblist();
332 void show_rpcblist();
333 char *sum_rpcb_entry_list();
334 void show_rpcb_entry_list();
335 
336 static char *procnames_short_4[] = {
337 	/*
338 	 * version 3 and 4 procs
339 	 */
340 	"Null",		/* 0 */
341 	"SET",		/* 1 */
342 	"UNSET",	/* 2 */
343 	"GETADDR",	/* 3 */
344 	"DUMP",		/* 4 */
345 	"BCAST",	/* 5 */
346 	"GETTIME",	/* 6 */
347 	"UADDR2TADDR",	/* 7 */
348 	"TADDR2UADDR",	/* 8 */
349 	/*
350 	 * version 4 procs only
351 	 */
352 	"GETVERSADDR",	/* 9 */
353 	"INDIRECT",	/* 10 */
354 	"GETADDRLIST",	/* 11 */
355 	"GETSTAT",	/* 12 */
356 };
357 
358 static char *procnames_long_4[] = {
359 	/*
360 	 * version 3 and 4 procs
361 	 */
362 	"Null procedure",			/* 0 */
363 	"Set address",				/* 1 */
364 	"Unset address",			/* 2 */
365 	"Get address",				/* 3 */
366 	"Dump the mappings",			/* 4 */
367 	"Broadcast call (no error)",		/* 5 */
368 	"Get the time",				/* 6 */
369 	"Universal to transport address",	/* 7 */
370 	"Transport to universal address",	/* 8 */
371 	/*
372 	 * version 4 procs only
373 	 */
374 	"Get address of specific version",	/* 9 */
375 	"Indirect call (return error)",		/* 10 */
376 	"Return addresses of prog/vers",	/* 11 */
377 	"Get statistics",			/* 12 */
378 };
379 
380 #define	MAXPROC_4		12
381 #define	RPCBPROC_NULL		0
382 
383 void
384 interpret_pmap_4(flags, type, xid, vers, proc, data, len)
385 	int flags, type, xid, vers, proc;
386 	char *data;
387 	int len;
388 {
389 	char *line;
390 	unsigned prog, ver;
391 	char buff1[MAXSTRINGLEN + 1];
392 	int iprog, ivers, iproc, ilen;
393 	extern int pi_frame;
394 	struct cache_struct *x, *find_callit();
395 	int trailer_done = 0;
396 
397 	if (proc < 0 || proc > MAXPROC_4)
398 		return;
399 
400 	if (proc == RPCBPROC_BCAST) {
401 		if (type == CALL) {
402 			iprog = getxdr_u_long();
403 			ivers = getxdr_u_long();
404 			iproc = getxdr_u_long();
405 			stash_callit(xid, pi_frame,
406 				iprog, ivers, iproc);
407 		} else {
408 			x = find_callit(xid);
409 		}
410 	}
411 
412 	if (flags & F_SUM) {
413 		if (setjmp(xdr_err)) {
414 			return;
415 		}
416 
417 		line = get_sum_line();
418 
419 		if (type == CALL) {
420 			(void) sprintf(line,
421 				"RPCBIND C %s",
422 				procnames_short_4[proc]);
423 			line += strlen(line);
424 			switch (proc) {
425 			case RPCBPROC_SET:
426 			case RPCBPROC_UNSET:
427 			case RPCBPROC_GETADDR:
428 			case RPCBPROC_GETVERSADDR:
429 			case RPCBPROC_GETADDRLIST:
430 				prog = getxdr_u_long();
431 				ver  = getxdr_u_long();
432 				(void) sprintf(line,
433 					" prog=%d (%s) vers=%d",
434 					prog, nameof_prog(prog),
435 					ver);
436 				break;
437 			case RPCBPROC_BCAST:
438 			case RPCBPROC_INDIRECT:
439 				(void) getxdr_u_long(); /* length */
440 				(void) sprintf(line,
441 					" prog=%s vers=%d proc=%d",
442 					nameof_prog(iprog),
443 					ivers, iproc);
444 				data += 16; /* prog+ver+proc+len */
445 				len -= 16;
446 				protoprint(flags, type, xid,
447 					iprog, ivers, iproc,
448 					data, len);
449 				break;
450 			default:
451 				break;
452 			}
453 
454 			check_retransmit(line, xid);
455 		} else {
456 			(void) sprintf(line, "RPCBIND R %s ",
457 				procnames_short_4[proc]);
458 			line += strlen(line);
459 			switch (proc) {
460 			case RPCBPROC_GETADDR:
461 			case RPCBPROC_TADDR2UADDR:
462 			case RPCBPROC_GETVERSADDR:
463 				(void) getxdr_string(buff1, MAXSTRINGLEN);
464 				(void) sprintf(line,
465 					" Uaddr=%s",
466 					buff1);
467 				break;
468 			case RPCBPROC_BCAST:
469 			case RPCBPROC_INDIRECT:
470 				(void) getxdr_string(buff1, MAXSTRINGLEN);
471 				ilen = getxdr_u_long();
472 				(void) sprintf(line, "Uaddr=%s len=%d",
473 					buff1, ilen);
474 				data += 16; /* prog+ver+proc+len */
475 				len -= 16;
476 				if (x != NULL) {
477 					protoprint(flags, type, xid,
478 						x->xid_prog,
479 						x->xid_vers,
480 						x->xid_proc,
481 						data, len);
482 				}
483 				break;
484 			case RPCBPROC_DUMP:
485 				(void) sprintf(line, "%s",
486 					sum_rpcblist());
487 				break;
488 			case RPCBPROC_GETTIME:
489 				(void) sprintf(line, "%s",
490 					getxdr_date());
491 				break;
492 			case RPCBPROC_GETADDRLIST:
493 				(void) sprintf(line, "%s",
494 					sum_rpcb_entry_list());
495 				break;
496 			default:
497 				break;
498 			}
499 		}
500 	}
501 
502 	if (flags & F_DTAIL) {
503 		show_header("RPCB:  ", "RPC Bind", len);
504 		show_space();
505 		if (setjmp(xdr_err)) {
506 			return;
507 		}
508 		(void) sprintf(get_line(0, 0),
509 			"Proc = %d (%s)",
510 			proc, procnames_long_4[proc]);
511 		if (type == CALL) {
512 			switch (proc) {
513 			case RPCBPROC_NULL:
514 				break;
515 			case RPCBPROC_SET:
516 			case RPCBPROC_UNSET:
517 			case RPCBPROC_GETADDR:
518 			case RPCBPROC_GETVERSADDR:
519 			case RPCBPROC_GETADDRLIST:
520 				(void) showxdr_u_long("Program = %d");
521 				(void) showxdr_u_long("Version = %d");
522 				(void) showxdr_string(64, "Netid   = %s");
523 				break;
524 			case RPCBPROC_DUMP:
525 				break;
526 			case RPCBPROC_BCAST:
527 			case RPCBPROC_INDIRECT:
528 				(void) sprintf(get_line(0, 0),
529 					"Program = %d (%s)",
530 					iprog, nameof_prog(iprog));
531 				(void) sprintf(get_line(0, 0),
532 					"Version = %d", ivers);
533 				(void) sprintf(get_line(0, 0),
534 					"Proc    = %d", iproc);
535 				(void) showxdr_u_long(
536 					"Callit data = %d bytes");
537 				show_trailer();
538 				trailer_done = 1;
539 				data += 16; /* prog+ver+proc+len */
540 				len -= 16;
541 				protoprint(flags, type, xid,
542 					iprog, ivers, iproc,
543 					data, len);
544 				break;
545 			case RPCBPROC_GETTIME:
546 				break;
547 			case RPCBPROC_UADDR2TADDR:
548 			case RPCBPROC_TADDR2UADDR:
549 				break;
550 			}
551 		} else {
552 			switch (proc) {
553 			case RPCBPROC_NULL:
554 			case RPCBPROC_SET:
555 			case RPCBPROC_UNSET:
556 				break;
557 			case RPCBPROC_GETADDR:
558 			case RPCBPROC_TADDR2UADDR:
559 			case RPCBPROC_GETVERSADDR:
560 				(void) showxdr_string(64, "Uaddr = %s");
561 				break;
562 			case RPCBPROC_DUMP:
563 				show_rpcblist();
564 				break;
565 			case RPCBPROC_BCAST:
566 			case RPCBPROC_INDIRECT:
567 				(void) showxdr_string(64, "Uaddr = %s");
568 				(void) showxdr_u_long("Length = %d bytes");
569 				show_trailer();
570 				trailer_done = 1;
571 				if (x != NULL) {
572 					protoprint(flags, type, xid,
573 						x->xid_prog,
574 						x->xid_vers,
575 						x->xid_proc,
576 						data, len);
577 				}
578 				break;
579 			case RPCBPROC_GETTIME:
580 				(void) showxdr_date("Time = %s");
581 				break;
582 			case RPCBPROC_UADDR2TADDR:
583 				break;
584 			case RPCBPROC_GETADDRLIST:
585 				show_rpcb_entry_list();
586 				break;
587 			}
588 		}
589 		if (!trailer_done)
590 			show_trailer();
591 	}
592 }
593 
594 char *
595 sum_rpcblist()
596 {
597 	int maps = 0;
598 	static char buff[MAXSTRINGLEN + 1];
599 
600 	if (setjmp(xdr_err)) {
601 		(void) sprintf(buff, "%d+ map(s) found", maps);
602 		return (buff);
603 	}
604 
605 	while (getxdr_u_long()) {
606 		(void) getxdr_u_long();		/* program */
607 		(void) getxdr_u_long();		/* version */
608 		(void) getxdr_string(buff, MAXSTRINGLEN); /* netid */
609 		(void) getxdr_string(buff, MAXSTRINGLEN); /* uaddr */
610 		(void) getxdr_string(buff, MAXSTRINGLEN); /* owner */
611 		maps++;
612 	}
613 
614 	(void) sprintf(buff, "%d map(s) found", maps);
615 	return (buff);
616 }
617 
618 void
619 show_rpcblist()
620 {
621 	unsigned prog, vers;
622 	char netid[MAXSTRINGLEN + 1], uaddr[MAXSTRINGLEN + 1];
623 	char owner[MAXSTRINGLEN + 1];
624 	int maps = 0;
625 
626 	if (setjmp(xdr_err)) {
627 		(void) sprintf(get_line(0, 0),
628 			" %d+ maps. (Frame is incomplete)",
629 			maps);
630 		return;
631 	}
632 
633 	show_space();
634 	(void) sprintf(get_line(0, 0),
635 		" Program Vers Netid        Uaddr              Owner");
636 
637 	while (getxdr_u_long()) {
638 		prog  = getxdr_u_long();
639 		vers  = getxdr_u_long();
640 		(void) getxdr_string(netid, MAXSTRINGLEN);
641 		(void) getxdr_string(uaddr, MAXSTRINGLEN);
642 		(void) getxdr_string(owner, MAXSTRINGLEN);
643 		(void) sprintf(get_line(0, 0),
644 			"%8d%5d %-12s %-18s %-10s (%s)",
645 			prog, vers,
646 			netid, uaddr, owner,
647 			nameof_prog(prog));
648 		maps++;
649 	}
650 
651 	(void) sprintf(get_line(0, 0), " (%d maps)", maps);
652 }
653 
654 char *
655 sum_rpcb_entry_list()
656 {
657 	int maps = 0;
658 	static char buff[MAXSTRINGLEN + 1];
659 
660 	if (setjmp(xdr_err)) {
661 		(void) sprintf(buff, "%d+ map(s) found", maps);
662 		return (buff);
663 	}
664 
665 	while (getxdr_u_long()) {
666 		(void) getxdr_string(buff, MAXSTRINGLEN); /* maddr	*/
667 		(void) getxdr_string(buff, MAXSTRINGLEN); /* nc_netid	*/
668 		(void) getxdr_u_long();			  /* nc_semantics */
669 		(void) getxdr_string(buff, MAXSTRINGLEN); /* nc_protofmly */
670 		(void) getxdr_string(buff, MAXSTRINGLEN); /* nc_proto	*/
671 		maps++;
672 	}
673 
674 	(void) sprintf(buff, "%d map(s) found", maps);
675 	return (buff);
676 }
677 
678 char *semantics_strs[] = {"", "CLTS", "COTS", "COTS-ORD", "RAW"};
679 
680 void
681 show_rpcb_entry_list()
682 {
683 	char maddr[MAXSTRINGLEN + 1], netid[MAXSTRINGLEN + 1];
684 	char protofmly[MAXSTRINGLEN + 1], proto[MAXSTRINGLEN + 1];
685 	unsigned sem;
686 	int maps = 0;
687 
688 	if (setjmp(xdr_err)) {
689 		(void) sprintf(get_line(0, 0),
690 			" %d+ maps. (Frame is incomplete)",
691 			maps);
692 		return;
693 	}
694 
695 	show_space();
696 	(void) sprintf(get_line(0, 0),
697 		" Maddr      Netid        Semantics Protofmly Proto");
698 
699 	while (getxdr_u_long()) {
700 		(void) getxdr_string(maddr, MAXSTRINGLEN);
701 		(void) getxdr_string(netid, MAXSTRINGLEN);
702 		sem  = getxdr_u_long();
703 		(void) getxdr_string(protofmly, MAXSTRINGLEN);
704 		(void) getxdr_string(proto, MAXSTRINGLEN);
705 		(void) sprintf(get_line(0, 0),
706 			"%-12s %-12s %-8s %-8s %-8s",
707 			maddr, netid,
708 			semantics_strs[sem],
709 			protofmly, proto);
710 		maps++;
711 	}
712 
713 	(void) sprintf(get_line(0, 0), " (%d maps)", maps);
714 }
715 
716 #define	CXID_CACHE_SIZE	16
717 struct cache_struct cxid_cache[CXID_CACHE_SIZE];
718 struct cache_struct *cxcpfirst	= &cxid_cache[0];
719 struct cache_struct *cxcp	= &cxid_cache[0];
720 struct cache_struct *cxcplast   = &cxid_cache[CXID_CACHE_SIZE - 1];
721 
722 struct cache_struct *
723 find_callit(xid)
724 	ulong_t xid;
725 {
726 	struct cache_struct *x;
727 
728 	for (x = cxcp; x >= cxcpfirst; x--)
729 		if (x->xid_num == xid)
730 			return (x);
731 	for (x = cxcplast; x > cxcp; x--)
732 		if (x->xid_num == xid)
733 			return (x);
734 	return (NULL);
735 }
736 
737 static void
738 stash_callit(xid, frame, prog, vers, proc)
739 	ulong_t xid;
740 	int frame, prog, vers, proc;
741 {
742 	struct cache_struct *x;
743 
744 	x = find_callit(xid);
745 	if (x == NULL) {
746 		x = cxcp++;
747 		if (cxcp > cxcplast)
748 			cxcp = cxcpfirst;
749 		x->xid_num = xid;
750 		x->xid_frame = frame;
751 	}
752 	x->xid_prog = prog;
753 	x->xid_vers = vers;
754 	x->xid_proc = proc;
755 }
756