xref: /illumos-gate/usr/src/cmd/adbgen/common/adbsub.c (revision 1a2d662a91cee3bf82f41cd47c7ae6f3825d9db2)
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 /*
24  * Copyright (c) 1983-1998 by Sun Microsystems, Inc.
25  * All rights reserved.
26  */
27 
28 /*
29  * Subroutines to be called by adbgen2.c, the C program generated
30  * by adbgen1.c.
31  */
32 
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <sys/types.h>
36 
37 off_t last_off;
38 int warnings = 1;
39 int warns = 0;
40 
41 /*
42  * User claims offset is ok.
43  * This usually follows call to another script, which we cannot handle.
44  */
45 void
46 offsetok(void)
47 {
48 	last_off = -1;
49 }
50 
51 /*
52  * Get adb.s dot to the right offset.
53  */
54 void
55 offset(off_t off)
56 {
57 	off_t off_diff;
58 
59 	if (last_off == -1) {
60 		last_off = off;
61 		return;
62 	}
63 	off_diff = off - last_off;
64 	if (off_diff) {
65 		if (off_diff > 0) {
66 			if (off_diff > 1) {
67 				printf("%ld", off_diff);
68 			}
69 			printf("+");
70 		}
71 		if (off_diff < 0) {
72 			if (off_diff < -1) {
73 				printf("%ld", -off_diff);
74 			}
75 			printf("-");
76 		}
77 	}
78 	last_off = off;
79 }
80 
81 /*
82  * Emit the format command, return the size.
83  */
84 int
85 do_fmt(char *acp)
86 {
87 	int rcount, width, sum, i;
88 	char *cp;
89 
90 	cp = acp;
91 	sum = rcount = 0;
92 	do {
93 		while (*cp >= '0' && *cp <= '9') {
94 			rcount = rcount * 10 + *cp++ - '0';
95 		}
96 		if (rcount == 0) {
97 			rcount = 1;
98 		}
99 		switch (*cp) {
100 		case 'e':
101 		case 'E':
102 		case 'F':
103 		case 'g':
104 		case 'G':
105 		case 'J':
106 			width = 8;
107 			break;
108 		case 'K':
109 #ifdef	_LP64
110 			width = 8;
111 #else	/* _LP64 */
112 			width = 4;
113 #endif	/* _LP64 */
114 			break;
115 		case 'X':
116 		case 'O':
117 		case 'Q':
118 		case 'D':
119 		case 'U':
120 		case 'f':
121 		case 'Y':
122 		case 'p':
123 		case 'P':
124 			width = 4;
125 			break;
126 		case 'x':
127 		case 'o':
128 		case 'q':
129 		case 'd':
130 		case 'u':
131 			width = 2;
132 			break;
133 		case 'v':
134 		case 'V':
135 		case 'b':
136 		case 'B':
137 		case 'c':
138 		case 'C':
139 		case '+':
140 			width = 1;
141 			break;
142 		case 'I':
143 		case 'a':
144 		case 'A':
145 		case 't':
146 		case 'r':
147 		case 'n':
148 			width = 0;
149 			break;
150 		case '-':
151 			width = -1;
152 			break;
153 		case 's':
154 		case 'S':
155 		case 'i':
156 			if (warnings) {
157 				fprintf(stderr,
158 				"Unknown format size \"%s\", assuming zero\n",
159 				acp);
160 				warns++;
161 			}
162 			width = 0;
163 			break;
164 		default:
165 			fprintf(stderr, "Unknown format size: %s\n", acp);
166 			exit(1);
167 		}
168 		for (i = 0; i < rcount; i++) {
169 			putchar(*cp);
170 		}
171 		cp++;
172 		sum += width * rcount;
173 	} while (*cp);
174 	return (sum);
175 }
176 
177 /*
178  * Format struct member, checking size.
179  */
180 void
181 format(char *name, size_t size, char *fmt)
182 {
183 	int fs;
184 
185 	fs = do_fmt(fmt);
186 	if (fs != size && warnings) {
187 		fprintf(stderr,
188 			"warning: \"%s\" size is %ld, \"%s\" width is %d\n",
189 			name, size, fmt, fs);
190 		warns++;
191 	}
192 	last_off += fs;
193 }
194 
195 /*
196  * Get the value at offset based on base.
197  */
198 void
199 indirect(off_t offset, size_t size, char *base, char *member)
200 {
201 	if (size == 8 || size == 4) {
202 		if (offset == 0) {
203 			printf("*%s", base);
204 		} else {
205 			printf("*(%s+0t%ld)", base, offset);
206 		}
207 	} else if (size == 2) {
208 		if (offset == 2) {
209 			printf("(*%s&0xffff)", base);
210 		} else {
211 			printf("(*(%s+0t%ld)&0xffff)", base, offset - 2);
212 		}
213 	} else if (size == 1) {
214 		if (offset == 3) {
215 			printf("(*%s&0xff)", base);
216 		} else {
217 			if ((offset & 0x1) == 0x1) {
218 				printf("(*(%s+0t%ld)&0xff)", base, offset - 3);
219 			} else {
220 				printf("((*(%s+0t%ld)&0xff00)/0x100)",
221 				    base, offset - 2);
222 			}
223 		}
224 	} else {
225 		fprintf(stderr, "Indirect size %ld not 1, 2, or 4: %s\n",
226 		    size, member);
227 		exit(1);
228 	}
229 }
230