| 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 | #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 | |
| 49 | struct regs { |
| 50 | union reg r[NREGS]; |
| 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 | |
| 60 | #define STRCMP(a, op, b) (strcmp((a), (b)) op 0) |
| 61 | #define STRNCMP(a, op, b, n) (strncmp((a), (b), (n)) op 0) |
| 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 | |
| 143 | static void setreg(union reg *r, struct seg **seg_inout, const char *p) |
| 144 | { |
| 145 | struct seg *seg; |
| 146 | const char *pp; |
| 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 | |
| 154 | switch (*p) { |
| 155 | case '-': |
| 156 | if (p[1]) r->i = LONG_REG(p); |
| 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; |
| 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; |
| 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 | |
| 212 | #if ULONG_MAX == 0xffffffff |
| 213 | printf("%3s = 0x%08lx = %20ld = %20lu", name, r->u, r->i, r->u); |
| 214 | #else |
| 215 | printf("%3s = 0x%016lx = %20ld = %20lu", name, r->u, r->i, r->u); |
| 216 | #endif |
| 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; |
| 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; |
| 261 | |
| 262 | prog = strrchr(argv[0], '/'); if (prog) prog++; else prog = argv[0]; |
| 263 | |
| 264 | if (argc < 2) |
| 265 | barf("usage: %s I [REG...]", |
| 266 | prog); |
| 267 | |
| 268 | j = parse_long("program index", argv[1], -1, N(x) - 1); |
| 269 | |
| 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 | } |
| 294 | |
| 295 | nseg = segp - seg; |
| 296 | call_example(j < 0 ? &nop : x[j], &r); |
| 297 | |
| 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__) |
| 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 | |
| 310 | printf("\tstatus: %ccf %cpf %caf %czf %csf %cdf %cof\n", |
| 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 ? '+' : '-'); |
| 318 | printf("\tcond:"); |
| 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)) |
| 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", |
| 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 ? '+' : '-'); |
| 341 | |
| 342 | #undef CF |
| 343 | #undef PF |
| 344 | #undef ZF |
| 345 | #undef SF |
| 346 | #undef OF |
| 347 | |
| 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 | |
| 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 | } |