Commit | Line | Data |
---|---|---|
06297a93 MW |
1 | #include <ctype.h> |
2 | #include <errno.h> | |
3 | #include <limits.h> | |
4 | #include <stdarg.h> | |
5 | #include <stdio.h> | |
6 | #include <stdlib.h> | |
7 | #include <string.h> | |
8 | ||
9 | union reg { | |
10 | unsigned char *p; | |
11 | long i; | |
12 | long u; | |
13 | }; | |
14 | ||
90c4eee3 MW |
15 | #if defined(__i386__) |
16 | # define GPREGS(_) \ | |
17 | _(a) _(b) _(c) _(d) _(si) _(di) _(bp) | |
18 | #elif defined(__x86_64__) | |
19 | # define GPREGS(_) \ | |
20 | _(a) _(b) _(c) _(d) _(si) _(di) _(bp) \ | |
21 | _(r8) _(r9) _(r10) _(r11) _(r12) _(r13) _(r14) _(r15) | |
22 | #elif defined(__arm__) | |
23 | # define GPREGS(_) \ | |
24 | _(r0) _(r1) _(r2) _(r3) _(r4) _(r5) _(r6) _(r7) \ | |
25 | _(r8) _(r9) _(r10) _(r11) _(r12) | |
26 | #elif defined(__aarch64__) | |
27 | # define GPREGS(_) \ | |
28 | _(x0) _(x1) _(x2) _(x3) _(x4) _(x5) _(x6) _(x7) \ | |
29 | _(x8) _(x9) _(x10) _(x11) _(x12) _(x13) _(x14) _(x15) | |
30 | #else | |
31 | # error "not supported" | |
32 | #endif | |
33 | ||
34 | enum { | |
35 | #define DEFCONST(r) R_##r, | |
36 | GPREGS(DEFCONST) | |
37 | #undef DEFCONST | |
38 | R_flags, | |
39 | NREGS | |
40 | }; | |
41 | ||
42 | static const char *const rname[] = { | |
43 | #define DEFNAME(r) #r, | |
44 | GPREGS(DEFNAME) | |
45 | #undef DEFNAME | |
46 | "f" | |
47 | }; | |
48 | ||
06297a93 | 49 | struct regs { |
90c4eee3 | 50 | union reg r[NREGS]; |
06297a93 MW |
51 | }; |
52 | ||
53 | struct seg { | |
54 | unsigned char *p; | |
55 | size_t sz; | |
56 | }; | |
57 | ||
58 | #define N(v) (sizeof(v)/sizeof((v)[0])) | |
59 | ||
90c4eee3 MW |
60 | #define STRCMP(a, op, b) (strcmp((a), (b)) op 0) |
61 | #define STRNCMP(a, op, b, n) (strncmp((a), (b), (n)) op 0) | |
06297a93 MW |
62 | #define CTYPE_HACK(func, ch) func((unsigned char)(ch)) |
63 | #define ISDIGIT(ch) CTYPE_HACK(isdigit, ch) | |
64 | #define ISSPACE(ch) CTYPE_HACK(isspace, ch) | |
65 | ||
66 | #define XCHG(_) \ | |
67 | _(x00) _(x01) _(x02) _(x03) _(x04) _(x05) _(x06) _(x07) \ | |
68 | _(x08) _(x09) _(x0a) _(x0b) _(x0c) _(x0d) _(x0e) _(x0f) \ | |
69 | _(x10) _(x11) _(x12) _(x13) _(x14) _(x15) _(x16) _(x17) \ | |
70 | _(x18) _(x19) _(x1a) _(x1b) _(x1c) _(x1d) _(x1e) _(x1f) \ | |
71 | _(x20) _(x21) _(x22) _(x23) _(x24) _(x25) _(x26) _(x27) \ | |
72 | _(x28) _(x29) _(x2a) _(x2b) _(x2c) _(x2d) _(x2e) _(x2f) \ | |
73 | _(x30) _(x31) _(x32) _(x33) _(x34) _(x35) _(x36) _(x37) \ | |
74 | _(x38) _(x39) _(x3a) _(x3b) _(x3c) _(x3d) _(x3e) _(x3f) | |
75 | ||
76 | #define DECL(x) extern const int x; | |
77 | XCHG(DECL) | |
78 | extern const int nop; | |
79 | ||
80 | static const int *x[] = { | |
81 | #define SLOT(x) &x, | |
82 | XCHG(SLOT) | |
83 | }; | |
84 | ||
85 | extern void call_example(const int *f, struct regs *r); | |
86 | ||
87 | static const char *prog = "???"; | |
88 | ||
89 | __attribute__((format(printf, 1, 2), noreturn)) | |
90 | static void barf(const char *m, ...) | |
91 | { | |
92 | va_list ap; | |
93 | ||
94 | va_start(ap, m); | |
95 | fprintf(stderr, "%s: ", prog); | |
96 | vfprintf(stderr, m, ap); | |
97 | putc('\n', stderr); | |
98 | va_end(ap); | |
99 | exit(127); | |
100 | } | |
101 | ||
102 | static void *xmalloc(size_t sz) | |
103 | { | |
104 | void *p; | |
105 | ||
106 | if (!sz) return (0); | |
107 | p = malloc(sz); | |
108 | if (!p) barf("malloc failed"); | |
109 | return (p); | |
110 | } | |
111 | ||
112 | #define DEF_PARSEINT(name, ty, strto) \ | |
113 | static ty parse_##name(const char *what, const char *p, ty min, ty max) \ | |
114 | { \ | |
115 | const char *pp = p; \ | |
116 | char *q; \ | |
117 | ty i; \ | |
118 | int err; \ | |
119 | \ | |
120 | if (ISSPACE(*p)) goto bad; \ | |
121 | err = errno; errno = 0; \ | |
122 | i = strto(p, &q, 0); \ | |
123 | if (errno) goto bad; \ | |
124 | if (*q) goto bad; \ | |
125 | if (i < min || i > max) goto bad; \ | |
126 | errno = err; \ | |
127 | return (i); \ | |
128 | \ | |
129 | bad: \ | |
130 | barf("bad %s `%s'", what, pp); \ | |
131 | } | |
132 | DEF_PARSEINT(long, long, strtol) | |
133 | DEF_PARSEINT(ulong, unsigned long, strtoul) | |
134 | ||
135 | static int hex_digit(char ch) | |
136 | { | |
137 | if ('0' <= ch && ch <= '9') return (ch - '0'); | |
138 | else if ('A' <= ch && ch <= 'F') return (ch - 'A' + 10); | |
139 | else if ('a' <= ch && ch <= 'f') return (ch - 'a' + 10); | |
140 | else return (-1); | |
141 | } | |
142 | ||
90c4eee3 | 143 | static void setreg(union reg *r, struct seg **seg_inout, const char *p) |
06297a93 MW |
144 | { |
145 | struct seg *seg; | |
90c4eee3 | 146 | const char *pp; |
06297a93 MW |
147 | unsigned char *q; |
148 | int hi, lo; | |
149 | size_t n; | |
150 | ||
151 | #define LONG_REG(p) (parse_long("signed register", (p), LONG_MIN, LONG_MAX)) | |
152 | #define ULONG_REG(p) (parse_ulong("unsigned register", (p), 0, ULONG_MAX)) | |
153 | ||
06297a93 MW |
154 | switch (*p) { |
155 | case '-': | |
156 | if (p[1]) r->i = LONG_REG(p); | |
06297a93 MW |
157 | break; |
158 | case 'i': | |
159 | if (p[1] != ':') goto bad; | |
160 | r->i = LONG_REG(p + 2); | |
161 | break; | |
162 | case 'u': | |
163 | if (p[1] != ':') goto bad; | |
164 | r->u = ULONG_REG(p + 2); | |
165 | break; | |
166 | case 'c': | |
167 | if (p[1] != ':' || p[3]) goto bad; | |
168 | r->u = p[2]; | |
169 | break; | |
170 | case 's': | |
171 | if (p[1] != ':') goto bad; | |
172 | pp = p + 2; n = strlen(pp) + 1; | |
173 | seg = (*seg_inout)++; seg->p = xmalloc(n); seg->sz = n; | |
174 | memcpy(seg->p, pp, n); r->p = seg->p; | |
175 | break; | |
176 | case 'm': | |
177 | if (p[1] != ':') goto bad; | |
178 | pp = p + 2; n = strlen(pp); if (n%2) goto bad; | |
179 | seg = (*seg_inout)++; seg->p = q = xmalloc(n/2); seg->sz = n/2; | |
180 | while (n) { | |
181 | hi = hex_digit(pp[0]); lo = hex_digit(pp[1]); | |
182 | if (hi < 0 || lo < 0) goto bad; | |
183 | *q++ = 16*hi + lo; n -= 2; pp += 2; | |
184 | } | |
185 | r->p = seg->p; | |
186 | break; | |
90c4eee3 MW |
187 | case 'z': |
188 | if (p[1] != ':') goto bad; | |
189 | n = parse_ulong("buffer length", p + 2, 0, ~(size_t)0); | |
190 | seg = (*seg_inout)++; seg->p = q = xmalloc(n); seg->sz = n; | |
191 | r->p = q; memset(q, 0, n); | |
192 | break; | |
06297a93 MW |
193 | default: |
194 | if (ISDIGIT(*p)) r->u = ULONG_REG(p); | |
195 | else if (*p == '+') r->i = LONG_REG(p); | |
196 | else if (*p == '\'' && p[2] == '\'' && !p[3]) r->u = p[1]; | |
197 | else goto bad; | |
198 | break; | |
199 | bad: | |
200 | barf("bad regspec `%s'", p); | |
201 | } | |
202 | ||
203 | #undef LONG_REG | |
204 | #undef ULONG_REG | |
205 | } | |
206 | ||
207 | static void dumpreg(const char *name, const union reg *r, | |
208 | const struct seg *seg, size_t nseg) | |
209 | { | |
210 | size_t i; | |
211 | ||
90c4eee3 MW |
212 | #if ULONG_MAX == 0xffffffff |
213 | printf("%3s = 0x%08lx = %20ld = %20lu", name, r->u, r->i, r->u); | |
214 | #else | |
06297a93 | 215 | printf("%3s = 0x%016lx = %20ld = %20lu", name, r->u, r->i, r->u); |
90c4eee3 | 216 | #endif |
06297a93 MW |
217 | if (r->u >= ' ' && r->u <= '~') printf(" = '%c'", (int)r->u); |
218 | for (i = 0; i < nseg; i++) { | |
219 | if (r->p == seg[i].p) | |
220 | printf(" = seg[%zu] base", i); | |
221 | else if (r->p == seg[i].p + seg[i].sz) | |
222 | printf(" = seg[%zu] limit", i); | |
223 | else if (seg[i].p < r->p && r->p < seg[i].p + seg[i].sz) | |
224 | printf(" = seg[%zu] + %zu", i, (size_t)(r->p - seg[i].p)); | |
225 | } | |
226 | putchar('\n'); | |
227 | } | |
228 | ||
229 | static void dumpseg(const struct seg *seg) | |
230 | { | |
231 | size_t i, j; | |
232 | unsigned char ch; | |
233 | ||
234 | for (i = 0; i < seg->sz; i += 8) { | |
235 | printf("\t%8zx :", i); | |
236 | for (j = 0; j < 8; j++) | |
237 | if (i + j >= seg->sz) printf(" **"); | |
238 | else printf(" %02x", seg->p[i + j]); | |
239 | printf(" : "); | |
240 | for (j = 0; j < 8; j++) | |
241 | if (i + j >= seg->sz) putchar('*'); | |
242 | else { | |
243 | ch = seg->p[i + j]; | |
244 | if (' ' <= ch && ch <= '~') putchar(ch); | |
245 | else putchar('.'); | |
246 | } | |
247 | putchar('\n'); | |
248 | } | |
249 | } | |
250 | ||
251 | int main(int argc, char *argv[]) | |
252 | { | |
253 | struct regs r; | |
254 | struct seg seg[16], *segp = seg; | |
90c4eee3 MW |
255 | size_t nseg, n; |
256 | const char *p; | |
257 | char *q; | |
258 | unsigned long f; | |
259 | int i, j, k; | |
260 | unsigned long l; | |
06297a93 MW |
261 | |
262 | prog = strrchr(argv[0], '/'); if (prog) prog++; else prog = argv[0]; | |
263 | ||
264 | if (argc < 2) | |
90c4eee3 | 265 | barf("usage: %s I [REG...]", |
06297a93 MW |
266 | prog); |
267 | ||
268 | j = parse_long("program index", argv[1], -1, N(x) - 1); | |
269 | ||
90c4eee3 MW |
270 | #if ULONG_MAX == 0xffffffff |
271 | # define DEAD 0xdeadbeef | |
272 | #else | |
273 | # define DEAD 0xdeadbeefdeadbeef | |
274 | #endif | |
275 | for (i = 0; i < NREGS - 1; i++) r.r[i].u = DEAD; | |
276 | #undef DEAD | |
277 | r.r[R_flags].u = 0; | |
278 | ||
279 | i = 0; | |
280 | argv += 2; | |
281 | while (*argv) { | |
282 | p = *argv++; | |
283 | if (ISDIGIT(*p)) { | |
284 | l = strtoul(p, &q, 10); | |
285 | if (l < NREGS && *q == '=') { p = q + 1; i = l; } | |
286 | } else for (k = 0; k < NREGS; k++) { | |
287 | n = strlen(rname[k]); | |
288 | if (STRNCMP(p, ==, rname[k], n) && p[n] == '=') | |
289 | { i = k; p += n + 1; break; } | |
290 | } | |
291 | if (i >= NREGS) barf("too many registers"); | |
292 | setreg(&r.r[i], &segp, p); i++; | |
293 | } | |
06297a93 | 294 | |
90c4eee3 | 295 | nseg = segp - seg; |
06297a93 MW |
296 | call_example(j < 0 ? &nop : x[j], &r); |
297 | ||
90c4eee3 MW |
298 | for (i = 0; i < NREGS; i++) dumpreg(rname[i], &r.r[i], seg, nseg); |
299 | ||
300 | f = r.r[R_flags].u; | |
301 | ||
302 | #if defined(__i386__) || defined(__x86_64__) | |
06297a93 MW |
303 | |
304 | #define CF (1 << 0) | |
305 | #define PF (1 << 2) | |
306 | #define ZF (1 << 6) | |
307 | #define SF (1 << 7) | |
308 | #define OF (1 << 11) | |
309 | ||
06297a93 | 310 | printf("\tstatus: %ccf %cpf %caf %czf %csf %cdf %cof\n", |
90c4eee3 MW |
311 | (f >> 0)&1u ? '+' : '-', |
312 | (f >> 2)&1u ? '+' : '-', | |
313 | (f >> 4)&1u ? '+' : '-', | |
314 | (f >> 6)&1u ? '+' : '-', | |
315 | (f >> 7)&1u ? '+' : '-', | |
316 | (f >> 10)&1u ? '+' : '-', | |
317 | (f >> 11)&1u ? '+' : '-'); | |
06297a93 | 318 | printf("\tcond:"); |
90c4eee3 MW |
319 | if (f&CF) printf(" c/b/nae"); else printf(" nc/ae/nb"); |
320 | if (f&ZF) printf(" e/z"); else printf(" ne/nz"); | |
321 | if (f&SF) printf(" s"); else printf(" ns"); | |
322 | if (f&OF) printf(" o"); else printf(" no"); | |
323 | if (f&PF) printf(" p"); else printf(" np"); | |
324 | if ((f&CF) || (f&ZF)) printf(" be/na"); else printf(" a/nbe"); | |
325 | if (!(f&OF) == !(f&SF)) printf(" ge/nl"); else printf(" l/nge"); | |
326 | if (!(f&OF) == !(f&SF) && !(f&ZF)) | |
06297a93 MW |
327 | printf(" g/nle"); else printf(" le/ng"); |
328 | putchar('\n'); | |
329 | printf("\tsystem: %ctf %cif iopl=%d %cnt " | |
330 | "%crf %cvm %cac %cvif %cvip %cid\n", | |
90c4eee3 MW |
331 | (f >> 8)&1u ? '+' : '-', |
332 | (f >> 9)&1u ? '+' : '-', | |
333 | (int)((f >> 12)&1u), | |
334 | (f >> 14)&1u ? '+' : '-', | |
335 | (f >> 16)&1u ? '+' : '-', | |
336 | (f >> 17)&1u ? '+' : '-', | |
337 | (f >> 18)&1u ? '+' : '-', | |
338 | (f >> 19)&1u ? '+' : '-', | |
339 | (f >> 20)&1u ? '+' : '-', | |
340 | (f >> 21)&1u ? '+' : '-'); | |
06297a93 MW |
341 | |
342 | #undef CF | |
343 | #undef PF | |
344 | #undef ZF | |
345 | #undef SF | |
346 | #undef OF | |
347 | ||
90c4eee3 MW |
348 | #elif defined(__arm__) |
349 | ||
350 | #define NF (1u << 31) | |
351 | #define ZF (1u << 30) | |
352 | #define CF (1u << 29) | |
353 | #define VF (1u << 28) | |
354 | ||
355 | { | |
356 | static const char | |
357 | *modetab[] = { "?00", "?01", "?02", "?03", "?04", "?05", "?06", "?07", | |
358 | "?08", "?09", "?10", "?11", "?12", "?13", "?14", "?15", | |
359 | "usr", "fiq", "irq", "svc", "?20", "?21", "mon", "abt", | |
360 | "?24", "?25", "hyp", "und", "?28", "?29", "?30", "sys" }, | |
361 | *condtab[] = { "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc", | |
362 | "hi", "ls", "ge", "lt", "gt", "le", "al", "nv" }; | |
363 | ||
364 | printf("\tuser: %cn %cz %cc %cv %cq ge=%c%c%c%c;", | |
365 | (f >> 31)&1u ? '+' : '-', | |
366 | (f >> 30)&1u ? '+' : '-', | |
367 | (f >> 29)&1u ? '+' : '-', | |
368 | (f >> 28)&1u ? '+' : '-', | |
369 | (f >> 27)&1u ? '+' : '-', | |
370 | (f >> 19)&1u ? '1' : '0', | |
371 | (f >> 18)&1u ? '1' : '0', | |
372 | (f >> 17)&1u ? '1' : '0', | |
373 | (f >> 16)&1u ? '1' : '0'); | |
374 | if (f&NF) printf(" mi"); else printf(" pl"); | |
375 | if (f&ZF) printf(" eq"); else printf(" ne"); | |
376 | if (f&CF) printf(" cs/hs"); else printf(" cc/lo"); | |
377 | if (f&VF) printf(" vs"); else printf(" vc"); | |
378 | if ((f&CF) && !(f&ZF)) printf(" hi"); else printf(" ls"); | |
379 | if (!(f&VF) == !(f&NF)) printf(" ge"); else printf(" lt"); | |
380 | if (!(f&VF) == !(f&NF) && !(f&ZF)) printf(" gt"); else printf(" le"); | |
381 | putchar('\n'); | |
382 | printf("\tsystem: %cj it=%s:%c%c%c%c %ce %ca %ci %cf %ct m=%s\n", | |
383 | (f >> 24)&1u ? '+' : '-', | |
384 | condtab[(f >> 12)&15u], | |
385 | (f >> 11)&1u ? '1' : '0', | |
386 | (f >> 10)&1u ? '1' : '0', | |
387 | (f >> 26)&1u ? '1' : '0', | |
388 | (f >> 25)&1u ? '1' : '0', | |
389 | (f >> 9)&1u ? '+' : '-', | |
390 | (f >> 8)&1u ? '+' : '-', | |
391 | (f >> 7)&1u ? '+' : '-', | |
392 | (f >> 6)&1u ? '+' : '-', | |
393 | (f >> 5)&1u ? '+' : '-', | |
394 | modetab[(f >> 0)&31u]); | |
395 | } | |
396 | ||
397 | #undef NF | |
398 | #undef ZF | |
399 | #undef CF | |
400 | #undef VF | |
401 | ||
402 | #elif defined(__aarch64__) | |
403 | ||
404 | #define NF (1u << 31) | |
405 | #define ZF (1u << 30) | |
406 | #define CF (1u << 29) | |
407 | #define VF (1u << 28) | |
408 | ||
409 | printf("\tuser: %cn %cz %cc %cv;", | |
410 | (f >> 31)&1u ? '+' : '-', | |
411 | (f >> 30)&1u ? '+' : '-', | |
412 | (f >> 29)&1u ? '+' : '-', | |
413 | (f >> 28)&1u ? '+' : '-'); | |
414 | if (f&NF) printf(" mi"); else printf(" pl"); | |
415 | if (f&ZF) printf(" eq"); else printf(" ne"); | |
416 | if (f&CF) printf(" cs/hs"); else printf(" cc/lo"); | |
417 | if (f&VF) printf(" vs"); else printf(" vc"); | |
418 | if ((f&CF) && !(f&ZF)) printf(" hi"); else printf(" ls"); | |
419 | if (!(f&VF) == !(f&NF)) printf(" ge"); else printf(" lt"); | |
420 | if (!(f&VF) == !(f&NF) && !(f&ZF)) printf(" gt"); else printf(" le"); | |
421 | putchar('\n'); | |
422 | ||
423 | #undef NF | |
424 | #undef ZF | |
425 | #undef CF | |
426 | #undef VF | |
427 | ||
428 | #else | |
429 | # error "not supported" | |
430 | #endif | |
431 | ||
06297a93 MW |
432 | for (i = 0; i < nseg; i++) |
433 | { printf("seg[%d] (%p):\n", i, seg[i].p); dumpseg(&seg[i]); } | |
434 | ||
435 | return (0); | |
436 | } |