chiark / gitweb /
Set and dump (almost) all of the ARM64 general registers.
[xchg-rax-rax] / main.c
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
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         _(x16) _(x17) _(x19) _(x20) _(x21) _(x22) _(x23)                \
31         _(x24) _(x25) _(x26) _(x27) _(x28) _(x29)
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
51 struct regs {
52   union reg r[NREGS];
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
62 #define STRCMP(a, op, b) (strcmp((a), (b)) op 0)
63 #define STRNCMP(a, op, b, n) (strncmp((a), (b), (n)) op 0)
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
145 static void setreg(union reg *r, struct seg **seg_inout, const char *p)
146 {
147   struct seg *seg;
148   const char *pp;
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
156   switch (*p) {
157     case '-':
158       if (p[1]) r->i = LONG_REG(p);
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;
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;
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
214 #if ULONG_MAX == 0xffffffff
215   printf("%3s =         0x%08lx = %20ld = %20lu", name, r->u, r->i, r->u);
216 #else
217   printf("%3s = 0x%016lx = %20ld = %20lu", name, r->u, r->i, r->u);
218 #endif
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;
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;
263
264   prog = strrchr(argv[0], '/'); if (prog) prog++; else prog = argv[0];
265
266   if (argc < 2)
267     barf("usage: %s I [REG...]",
268          prog);
269
270   j = parse_long("program index", argv[1], -1, N(x) - 1);
271
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   }
296
297   nseg = segp - seg;
298   call_example(j < 0 ? &nop : x[j], &r);
299
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__)
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
312   printf("\tstatus: %ccf %cpf %caf %czf %csf %cdf %cof\n",
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 ? '+' : '-');
320   printf("\tcond:");
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))
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",
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 ? '+' : '-');
343
344 #undef CF
345 #undef PF
346 #undef ZF
347 #undef SF
348 #undef OF
349
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
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 }