chiark / gitweb /
.gitignore: We should have one of these.
[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 struct regs {
16   union reg
17     a, b, c, d, si, di, bp, f,
18     r8, r9, r10, r11, r12, r13, r14, r15;
19 };
20
21 struct seg {
22   unsigned char *p;
23   size_t sz;
24 };
25
26 #define N(v) (sizeof(v)/sizeof((v)[0]))
27
28 #define CTYPE_HACK(func, ch) func((unsigned char)(ch))
29 #define ISDIGIT(ch) CTYPE_HACK(isdigit, ch)
30 #define ISSPACE(ch) CTYPE_HACK(isspace, ch)
31
32 #define XCHG(_)                                                         \
33   _(x00) _(x01) _(x02) _(x03) _(x04) _(x05) _(x06) _(x07)               \
34   _(x08) _(x09) _(x0a) _(x0b) _(x0c) _(x0d) _(x0e) _(x0f)               \
35   _(x10) _(x11) _(x12) _(x13) _(x14) _(x15) _(x16) _(x17)               \
36   _(x18) _(x19) _(x1a) _(x1b) _(x1c) _(x1d) _(x1e) _(x1f)               \
37   _(x20) _(x21) _(x22) _(x23) _(x24) _(x25) _(x26) _(x27)               \
38   _(x28) _(x29) _(x2a) _(x2b) _(x2c) _(x2d) _(x2e) _(x2f)               \
39   _(x30) _(x31) _(x32) _(x33) _(x34) _(x35) _(x36) _(x37)               \
40   _(x38) _(x39) _(x3a) _(x3b) _(x3c) _(x3d) _(x3e) _(x3f)
41
42 #define DECL(x) extern const int x;
43 XCHG(DECL)
44 extern const int nop;
45
46 static const int *x[] = {
47 #define SLOT(x) &x,
48   XCHG(SLOT)
49 };
50
51 extern void call_example(const int *f, struct regs *r);
52
53 static const char *prog = "???";
54
55 __attribute__((format(printf, 1, 2), noreturn))
56 static void barf(const char *m, ...)
57 {
58   va_list ap;
59
60   va_start(ap, m);
61   fprintf(stderr, "%s: ", prog);
62   vfprintf(stderr, m, ap);
63   putc('\n', stderr);
64   va_end(ap);
65   exit(127);
66 }
67
68 static void *xmalloc(size_t sz)
69 {
70   void *p;
71
72   if (!sz) return (0);
73   p = malloc(sz);
74   if (!p) barf("malloc failed");
75   return (p);
76 }
77
78 #define DEF_PARSEINT(name, ty, strto)                                   \
79   static ty parse_##name(const char *what, const char *p, ty min, ty max) \
80   {                                                                     \
81     const char *pp = p;                                                 \
82     char *q;                                                            \
83     ty i;                                                               \
84     int err;                                                            \
85                                                                         \
86     if (ISSPACE(*p)) goto bad;                                          \
87     err = errno; errno = 0;                                             \
88     i = strto(p, &q, 0);                                                \
89     if (errno) goto bad;                                                \
90     if (*q) goto bad;                                                   \
91     if (i < min || i > max) goto bad;                                   \
92     errno = err;                                                        \
93     return (i);                                                         \
94                                                                         \
95   bad:                                                                  \
96     barf("bad %s `%s'", what, pp);                                      \
97   }
98 DEF_PARSEINT(long, long, strtol)
99 DEF_PARSEINT(ulong, unsigned long, strtoul)
100
101 static int hex_digit(char ch)
102 {
103   if ('0' <= ch && ch <= '9') return (ch - '0');
104   else if ('A' <= ch && ch <= 'F') return (ch - 'A' + 10);
105   else if ('a' <= ch && ch <= 'f') return (ch - 'a' + 10);
106   else return (-1);
107 }
108
109 static void setreg(union reg *r,
110                    struct seg **seg_inout,
111                    int *i_inout, int argc, char *argv[])
112 {
113   struct seg *seg;
114   const char *p, *pp;
115   unsigned char *q;
116   int hi, lo;
117   size_t n;
118
119 #define LONG_REG(p) (parse_long("signed register", (p), LONG_MIN, LONG_MAX))
120 #define ULONG_REG(p) (parse_ulong("unsigned register", (p), 0, ULONG_MAX))
121
122   p = *i_inout >= argc ? "-" : argv[(*i_inout)++];
123   switch (*p) {
124     case '-':
125       if (p[1]) r->i = LONG_REG(p);
126       else r->u = 0xdeadbeefdeadbeef;
127       break;
128     case 'i':
129       if (p[1] != ':') goto bad;
130       r->i = LONG_REG(p + 2);
131       break;
132     case 'u':
133       if (p[1] != ':') goto bad;
134       r->u = ULONG_REG(p + 2);
135       break;
136     case 'c':
137       if (p[1] != ':' || p[3]) goto bad;
138       r->u = p[2];
139       break;
140     case 's':
141       if (p[1] != ':') goto bad;
142       pp = p + 2; n = strlen(pp) + 1;
143       seg = (*seg_inout)++; seg->p = xmalloc(n); seg->sz = n;
144       memcpy(seg->p, pp, n); r->p = seg->p;
145       break;
146     case 'm':
147       if (p[1] != ':') goto bad;
148       pp = p + 2; n = strlen(pp); if (n%2) goto bad;
149       seg = (*seg_inout)++; seg->p = q = xmalloc(n/2); seg->sz = n/2;
150       while (n) {
151         hi = hex_digit(pp[0]); lo = hex_digit(pp[1]);
152         if (hi < 0 || lo < 0) goto bad;
153         *q++ = 16*hi + lo; n -= 2; pp += 2;
154       }
155       r->p = seg->p;
156       break;
157     default:
158       if (ISDIGIT(*p)) r->u = ULONG_REG(p);
159       else if (*p == '+') r->i = LONG_REG(p);
160       else if (*p == '\'' && p[2] == '\'' && !p[3]) r->u = p[1];
161       else goto bad;
162       break;
163     bad:
164       barf("bad regspec `%s'", p);
165   }
166
167 #undef LONG_REG
168 #undef ULONG_REG
169 }
170
171 static void dumpreg(const char *name, const union reg *r,
172                     const struct seg *seg, size_t nseg)
173 {
174   size_t i;
175
176   printf("%3s = 0x%016lx = %20ld = %20lu", name, r->u, r->i, r->u);
177   if (r->u >= ' ' && r->u <= '~') printf(" = '%c'", (int)r->u);
178   for (i = 0; i < nseg; i++) {
179     if (r->p == seg[i].p)
180       printf(" = seg[%zu] base", i);
181     else if (r->p == seg[i].p + seg[i].sz)
182       printf(" = seg[%zu] limit", i);
183     else if (seg[i].p < r->p && r->p < seg[i].p + seg[i].sz)
184       printf(" = seg[%zu] + %zu", i, (size_t)(r->p - seg[i].p));
185   }
186   putchar('\n');
187 }
188
189 static void dumpseg(const struct seg *seg)
190 {
191   size_t i, j;
192   unsigned char ch;
193
194   for (i = 0; i < seg->sz; i += 8) {
195     printf("\t%8zx :", i);
196     for (j = 0; j < 8; j++)
197       if (i + j >= seg->sz) printf(" **");
198       else printf(" %02x", seg->p[i + j]);
199     printf(" : ");
200     for (j = 0; j < 8; j++)
201       if (i + j >= seg->sz) putchar('*');
202       else {
203         ch = seg->p[i + j];
204         if (' ' <= ch && ch <= '~') putchar(ch);
205         else putchar('.');
206       }
207     putchar('\n');
208   }
209 }
210
211 int main(int argc, char *argv[])
212 {
213   struct regs r;
214   struct seg seg[16], *segp = seg;
215   size_t nseg;
216   int i, j;
217
218   prog = strrchr(argv[0], '/'); if (prog) prog++; else prog = argv[0];
219
220   if (argc < 2)
221     barf("usage: %s I [A B C D SI DI BP R8 R9 R10 R11 R12 R13 R14 R15 F]",
222          prog);
223
224   j = parse_long("program index", argv[1], -1, N(x) - 1);
225
226   i = 2;
227   setreg(&r.a, &segp, &i, argc, argv);
228   setreg(&r.b, &segp, &i, argc, argv);
229   setreg(&r.c, &segp, &i, argc, argv);
230   setreg(&r.d, &segp, &i, argc, argv);
231   setreg(&r.si, &segp, &i, argc, argv);
232   setreg(&r.di, &segp, &i, argc, argv);
233   setreg(&r.bp, &segp, &i, argc, argv);
234   setreg(&r.r8, &segp, &i, argc, argv);
235   setreg(&r.r9, &segp, &i, argc, argv);
236   setreg(&r.r10, &segp, &i, argc, argv);
237   setreg(&r.r11, &segp, &i, argc, argv);
238   setreg(&r.r12, &segp, &i, argc, argv);
239   setreg(&r.r13, &segp, &i, argc, argv);
240   setreg(&r.r14, &segp, &i, argc, argv);
241   setreg(&r.r15, &segp, &i, argc, argv);
242   setreg(&r.f, &segp, &i, argc, argv);
243   nseg = segp - seg;
244
245   call_example(j < 0 ? &nop : x[j], &r);
246
247   dumpreg("rax", &r.a, seg, nseg);
248   dumpreg("rbx", &r.b, seg, nseg);
249   dumpreg("rcx", &r.c, seg, nseg);
250   dumpreg("rdx", &r.d, seg, nseg);
251   dumpreg("rsi", &r.si, seg, nseg);
252   dumpreg("rdi", &r.di, seg, nseg);
253   dumpreg("rbp", &r.bp, seg, nseg);
254   dumpreg("rbp", &r.bp, seg, nseg);
255   dumpreg("r8", &r.r8, seg, nseg);
256   dumpreg("r9", &r.r9, seg, nseg);
257   dumpreg("r10", &r.r10, seg, nseg);
258   dumpreg("r11", &r.r11, seg, nseg);
259   dumpreg("r12", &r.r12, seg, nseg);
260   dumpreg("r13", &r.r13, seg, nseg);
261   dumpreg("r14", &r.r14, seg, nseg);
262   dumpreg("r15", &r.r15, seg, nseg);
263
264 #define CF (1 <<  0)
265 #define PF (1 <<  2)
266 #define ZF (1 <<  6)
267 #define SF (1 <<  7)
268 #define OF (1 << 11)
269
270   dumpreg("f", &r.f, seg, nseg);
271   printf("\tstatus: %ccf %cpf %caf %czf %csf %cdf %cof\n",
272          (r.f.u >>  0)&1u ? '+' : '-',
273          (r.f.u >>  2)&1u ? '+' : '-',
274          (r.f.u >>  4)&1u ? '+' : '-',
275          (r.f.u >>  6)&1u ? '+' : '-',
276          (r.f.u >>  7)&1u ? '+' : '-',
277          (r.f.u >> 10)&1u ? '+' : '-',
278          (r.f.u >> 11)&1u ? '+' : '-');
279   printf("\tcond:");
280   if (r.f.u&CF) printf(" c/b/nae"); else printf(" nc/ae/nb");
281   if (r.f.u&ZF) printf(" e/z"); else printf(" ne/nz");
282   if (r.f.u&SF) printf(" s"); else printf(" ns");
283   if (r.f.u&OF) printf(" o"); else printf(" no");
284   if (r.f.u&PF) printf(" p"); else printf(" np");
285   if ((r.f.u&CF) || (r.f.u&ZF)) printf(" be/na"); else printf(" a/nbe");
286   if (!(r.f.u&OF) == !(r.f.u&SF)) printf(" ge/nl"); else printf(" l/nge");
287   if (!(r.f.u&OF) == !(r.f.u&SF) && !(r.f.u&ZF))
288     printf(" g/nle"); else printf(" le/ng");
289   putchar('\n');
290   printf("\tsystem: %ctf %cif iopl=%d %cnt "
291                         "%crf %cvm %cac %cvif %cvip %cid\n",
292          (r.f.u >>  8)&1u ? '+' : '-',
293          (r.f.u >>  9)&1u ? '+' : '-',
294          (int)((r.f.u >> 12)&1u),
295          (r.f.u >> 14)&1u ? '+' : '-',
296          (r.f.u >> 16)&1u ? '+' : '-',
297          (r.f.u >> 17)&1u ? '+' : '-',
298          (r.f.u >> 18)&1u ? '+' : '-',
299          (r.f.u >> 19)&1u ? '+' : '-',
300          (r.f.u >> 20)&1u ? '+' : '-',
301          (r.f.u >> 21)&1u ? '+' : '-');
302
303 #undef CF
304 #undef PF
305 #undef ZF
306 #undef SF
307 #undef OF
308
309   for (i = 0; i < nseg; i++)
310     { printf("seg[%d] (%p):\n", i, seg[i].p); dumpseg(&seg[i]); }
311
312   return (0);
313 }