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