| 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 | } |