root/src/monitor.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. adrhash
  2. getbps
  3. addbps
  4. delbps
  5. listbps
  6. freebpslist
  7. freebps
  8. monargstok
  9. monlinetok
  10. stracmp
  11. warn_ignore_arg
  12. mon_break
  13. mon_dump
  14. monitorcmd
  15. free_moncmdline
  16. monquit
  17. monitor

   1 #include "monitor.h"
   2 
   3 /**
   4  * @brief ブレークポイント表
   5  */
   6 static BPSLIST *bps[BPSTABSIZE];
   7 
   8 /**
   9  * @brief comet2monitorのプロンプト
  10  */
  11 static char *monitor_prompt = "(comet2 monitor)";
  12 
  13 unsigned adrhash(WORD adr)
  14 {
  15     HKEY *key[1];
  16     unsigned h;
  17     key[0] = malloc_chk(sizeof(HKEY), "adrhash.key");
  18     key[0]->type = INT;
  19     key[0]->val.i = adr;
  20     h = hash(1, key, BPSTABSIZE);
  21     FREE(key[0]);
  22     return h;
  23 }
  24 
  25 bool getbps(WORD adr)
  26 {
  27     BPSLIST *p = NULL;
  28 
  29     for(p = bps[adrhash(adr)]; p != NULL; p = p->next) {
  30         if(p->adr == adr) {
  31             return true;
  32         }
  33     }
  34     return false;
  35 }
  36 
  37 bool addbps(WORD adr)
  38 {
  39     BPSLIST *p = NULL;
  40     unsigned h = 0;
  41 
  42     /* 登録されたラベルを検索。すでに登録されている場合は終了 */
  43     if(getbps(adr) == true) {
  44         fprintf(stderr, "%04X: Breakpoint is already defined.\n", adr);
  45         return false;
  46     }
  47     /* メモリを確保 */
  48     p = malloc_chk(sizeof(BPSLIST), "bps.next");
  49     /* アドレスを設定 */
  50     p->adr = adr;
  51     /* ハッシュ表へ追加 */
  52     p->next = bps[h = adrhash(adr)];
  53     bps[h] = p;
  54     return true;
  55 }
  56 
  57 bool delbps(WORD adr)
  58 {
  59     BPSLIST *p = NULL;
  60     BPSLIST *q = NULL;
  61     unsigned h = 0;
  62     bool res = false;
  63 
  64     p = bps[h = adrhash(adr)];
  65     if(p != NULL) {
  66         if(p->adr == adr) {
  67             if(p->next == NULL) {
  68                 FREE(bps[h]);
  69             } else {
  70                 bps[h] = p->next;
  71                 FREE(p);
  72             }
  73             res = true;
  74         } else {
  75             for(; p->next != NULL; p = p->next) {
  76                 q = p->next;
  77                 if(q->adr == adr) {
  78                     p->next = q->next;
  79                     FREE(q);
  80                     res = true;
  81                     break;
  82                 }
  83             }
  84         }
  85     }
  86     return res;
  87 }
  88 
  89 void listbps()
  90 {
  91     int cnt = 0;
  92     BPSLIST *p = NULL;
  93 
  94     fprintf(stdout, "List of breakpoints\n");
  95     for(int i = 0; i < BPSTABSIZE; i++) {
  96         for(p = bps[i]; p != NULL; p = p->next) {
  97             fprintf(stdout, "#%04X\n", p->adr);
  98             cnt++;
  99         }
 100     }
 101     if(cnt == 0) {
 102         fprintf(stdout, "(No breakpoints.)\n");
 103     }
 104 }
 105 
 106 void freebpslist(BPSLIST *head)
 107 {
 108     BPSLIST *p = NULL;
 109     BPSLIST *q = NULL;
 110     for(p = head; p != NULL; p = q) {
 111         q = p->next;
 112         FREE(p);
 113     }
 114 }
 115 
 116 void freebps()
 117 {
 118     for(int i = 0; i < BPSTABSIZE; i++) {
 119         freebpslist(bps[i]);
 120         bps[i] = NULL;
 121     }
 122 }
 123 
 124 MONARGS *monargstok(const char *str)
 125 {
 126     MONARGS *args = malloc_chk(sizeof(MONARGS), "args");
 127     char *tok = NULL;
 128     char *p = NULL;
 129     char sepc = ' ';
 130 
 131     args->argc = 0;
 132     if(!str || !str[0]) {
 133         return args;
 134     }
 135     tok = p = strdup_chk(str, "argstok.p");
 136     do {
 137         int i = strcspn(p, " ");
 138         sepc = p[i];
 139         args->argv[(args->argc)++] = strndup_chk(p, i, "args->argv[]");
 140         p += i + 1;
 141     } while(sepc == ' ');
 142     FREE(tok);
 143     return args;
 144 }
 145 
 146 MONCMDLINE *monlinetok(const char *line)
 147 {
 148     char *tokens = NULL;
 149     char *p = NULL;
 150     int i = 0;
 151     MONCMDLINE *moncmdl = NULL;
 152 
 153     if(!line[0] || line[0] == '\n') {
 154         return NULL;
 155     }
 156     p = tokens = strdup_chk(line, "tokens");
 157     /* コメントを削除 */
 158     strip_casl2_comment(p);
 159     /* 文字列末尾の改行と空白を削除 */
 160     strip_end(p);
 161 
 162     moncmdl = malloc_chk(sizeof(MONCMDLINE), "moncmdl");
 163     /* コマンドの取得 */
 164     i = strcspn(p, " \t\n");
 165     moncmdl->cmd = strndup_chk(p, i, "moncmdl->cmd");
 166     /* コマンドと引数の間の空白をスキップ */
 167     p += i;
 168     while(*p == ' ' || *p == '\t') {
 169         p++;
 170     }
 171     /* 引数として、改行までの文字列を取得 */
 172     if(strcspn(p, "\n") > 0) {
 173         moncmdl->args = monargstok(p);
 174     } else {
 175         moncmdl->args = malloc_chk(sizeof(MONARGS), "moncmdl.args");
 176         moncmdl->args->argc = 0;
 177     }
 178     FREE(tokens);
 179     return moncmdl;
 180 }
 181 
 182 bool stracmp(char *str1, int str2c, char *str2v[])
 183 {
 184     int i;
 185     if(str1 == NULL) {
 186         return false;
 187     }
 188     for(i = 0; i < str2c; i++) {
 189         if(strcmp(str1, str2v[i]) == 0) {
 190             return true;
 191         }
 192     }
 193     return false;
 194 }
 195 
 196 void warn_ignore_arg(int argc, char *argv[])
 197 {
 198     int i;
 199     for(i = 0; i < argc; i++) {
 200         if(i > 0) {
 201             fprintf(stderr, " ");
 202         }
 203         fprintf(stderr, "%s", argv[i]);
 204     }
 205     fprintf(stderr, ": ignored.\n");
 206 }
 207 
 208 void mon_break(int argc, char *argv[])
 209 {
 210     WORD w;
 211     int i = 0;
 212     if(stracmp(argv[0], 2, (char* []){"l", "list"})) {
 213         i++;
 214         listbps();
 215     } else if(stracmp(argv[0], 2, (char* []){"r", "reset"})) {
 216         i++;
 217         freebps();
 218         fprintf(stdout, "All breakpoints are deleted.\n");
 219     } else {
 220         if(argc > 1) {
 221             if((w = nh2word(argv[1])) == 0x0) {
 222                 fprintf(stderr, "%s: address error\n", argv[1]);
 223             }
 224         }
 225         if(stracmp(argv[0], 2, (char* []){"a", "add"})) {
 226             i += 2;
 227             if(addbps(w) == true) {
 228                 fprintf(stdout, "#%04X: breakpoint added\n", w);
 229             } else {
 230                 fprintf(stdout, "No breakpoint added\n");
 231             }
 232         } else if(stracmp(argv[0], 2, (char* []){"d", "del"})) {
 233             i += 2;
 234             if(delbps(w) == true) {
 235                 fprintf(stdout, "#%04X: breakpoint deleted\n", w);
 236             } else {
 237                 fprintf(stdout, "No breakpoint deleted\n");
 238             }
 239         } else if(stracmp(argv[0], 3, (char* []){"?", "h", "help"})) {
 240             i++;
 241             fprintf(stdout, "breakpoint manipulate:\n");
 242             fprintf(stdout, "    b[reak] a[dd] <address>\n");
 243             fprintf(stdout, "    b[reak] d[el] <address>\n");
 244             fprintf(stdout, "    b[reak] l[ist]\n");
 245             fprintf(stdout, "    b[reak] r[eset]\n");
 246         } else {
 247             fprintf(stderr, "%s: Not breakpoint manipulate command. see `b ?'.\n", argv[0]);
 248         }
 249         if(argc > i) {
 250             warn_ignore_arg(argc - i, argv + i);
 251         }
 252     }
 253 }
 254 
 255 void mon_dump(int argc, char *argv[])
 256 {
 257     int i = 0;
 258     WORD dump_start = 0, dump_end = 0x40;
 259     if(argc > 0 && stracmp(argv[0], 2, (char* []){"a", "auto"})) {
 260         execmode.dump = true;
 261         i++;
 262     } else if(argc > 0 && stracmp(argv[0], 2, (char* []){"no", "noauto"})) {
 263         execmode.dump = false;
 264         i++;
 265     }
 266     if(argc > i) {
 267         dump_start = nh2word(argv[i++]);
 268         if(argc > i) {
 269             if(argv[i][0] =='+') {
 270                 dump_end = dump_start + nh2word(argv[i] + 1);
 271             } else {
 272                 dump_end = nh2word(argv[i]);
 273             }
 274         } else {
 275             dump_end += dump_start;
 276         }
 277         i++;
 278     }
 279     if(argc > i) {
 280         warn_ignore_arg(argc - i, argv + i);
 281     }
 282     dumpmemory(dump_start, dump_end);
 283     execmode.dump_start = dump_start;
 284     execmode.dump_end = dump_end;
 285 }
 286 
 287 MONCMDTYPE monitorcmd(char *cmd, MONARGS *args)
 288 {
 289     MONCMDTYPE cmdtype = MONREPEAT;
 290     if(stracmp(cmd, 2, (char* []){"a", "assemble"})) {
 291         if(args->argc == 0) {
 292             fprintf(stderr, "Error: Input file name.\n");
 293         } else if(args->argc == 1) {
 294             assemble(1, (char* []){args->argv[0]}, 0);
 295         } else {
 296             assemble(1, (char* []){args->argv[0]}, nh2word(args->argv[1]));
 297         }
 298     } else if(stracmp(cmd, 2, (char* []){"b", "break"})) {
 299         mon_break(args->argc, args->argv);
 300     } else if(stracmp(cmd, 2, (char* []){"c", "continue"})) {
 301         execmode.step = false;
 302         cmdtype = MONNEXT;
 303     } else if(stracmp(cmd, 2, (char* []){"d", "dump"})) {
 304         mon_dump(args->argc, args->argv);
 305     } else if(stracmp(cmd, 2, (char* []){"l", "load"})) {
 306         execptr->end = loadassemble(args->argv[0], nh2word(args->argv[1]));
 307     } else if(stracmp(cmd, 2, (char* []){"n", "next"})) {
 308         execmode.step = true;
 309         cmdtype = MONNEXT;
 310     } else if(stracmp(cmd, 2, (char* []){"q", "quit"})) {
 311         fprintf(stdout, "Quit: COMET II monitor\n");
 312         cmdtype = MONQUIT;
 313     } else if(stracmp(cmd, 2, (char* []){"r", "reverse"})) {
 314         if(args->argc == 2) {
 315             disassemble_memory(nh2word(args->argv[0]), nh2word(args->argv[1]));
 316         }
 317     } else if(stracmp(cmd, 1, (char* []){"reset"})) {
 318         fprintf(stdout, "Reset COMET II.\n");
 319         reset(sys->memsize, sys->clocks);     /* COMET II仮想マシンのリセット */
 320     } else if(stracmp(cmd, 2, (char* []){"t", "trace"})) {
 321         if(args->argc > 0 && stracmp(args->argv[0], 2, (char* []){"a", "auto"})) {
 322             execmode.logical = false;
 323             execmode.trace = true;
 324         } else if(args->argc > 0 && stracmp(args->argv[0], 2, (char* []){"no", "noauto"})) {
 325             execmode.trace = false;
 326         } else {
 327             fprintf(stdout, "#%04X: Register::::\n", sys->cpu->pr);
 328             dspregister();
 329         }
 330     } else if(stracmp(cmd, 2, (char* []){"T", "tracelogical"})) {
 331         if(args->argc > 0 && stracmp(args->argv[0], 2, (char* []){"a", "auto"})) {
 332             execmode.logical = true;
 333             execmode.trace = true;
 334         } else if(args->argc > 0 && stracmp(args->argv[0], 2, (char* []){"no", "noauto"})) {
 335             execmode.trace = false;
 336         } else {
 337             fprintf(stdout, "#%04X: Register::::\n", sys->cpu->pr);
 338             dspregister();
 339         }
 340     } else if(stracmp(cmd, 3, (char* []){"?", "h", "help"})) {
 341         fprintf(stdout, "b[reak] -- Manipulate Breakpoints. See details, `b ?'.\n");
 342         fprintf(stdout, "c[ontinue] -- Continue running your program.\n");
 343         fprintf(stdout, "d[ump] -- Display memory dump. `d[ump] a[uto]/n[oauto]' set auto/noauto display.\n");
 344         fprintf(stdout, "l[oad] -- Load object from a file to the memory. `l[oad] <filepath> <address>' if address is omitted, load to address 0.\n");
 345         fprintf(stdout, "n[ext] -- Go next instruction.\n");
 346         fprintf(stdout, "q[uit] -- Quit running your program.\n");
 347         fprintf(stdout, "reset -- Reset the system.\n");
 348         fprintf(stdout, "r[everse] -- Disassemble memory. `r[everse] <start address> <end address>.\n");
 349         fprintf(stdout, "s[ave] -- Save object from the memory to a file. `s[ave] <filepath> [<start address1> [<end address>]]' if <start address> and <end address> is omitted, save the whole memory. if <end address> is omitted, save the memory after <start address>.\n");
 350         fprintf(stdout, "t[race] -- Display CPU register. `t[race] a[uto]/n[oauto]' set auto/noauto display. \n");
 351         fprintf(stdout, "T[race] -- Display CPU register as logical value. `t[race] a[uto]/n[oauto]' set auto/noauto display. \n");
 352         fprintf(stdout, "?/h[elp] -- Display this help.\n");
 353     }
 354     return cmdtype;
 355 }
 356 
 357 void free_moncmdline(MONCMDLINE *moncmdl)
 358 {
 359     int i;
 360     assert(moncmdl != NULL);
 361     if(moncmdl->args != NULL) {
 362         for(i = 0;  i < moncmdl->args->argc; i++) {
 363             FREE(moncmdl->args->argv[i]);
 364         }
 365         FREE(moncmdl->args);
 366     }
 367     if(moncmdl->cmd != NULL) {
 368         FREE(moncmdl->cmd);
 369     }
 370     if(moncmdl != NULL) {
 371         FREE(moncmdl);
 372     }
 373 }
 374 
 375 int monquit()
 376 {
 377     int stat = 0;
 378     shutdown();
 379     freebps();
 380     free_cmdtable(HASH_CMDTYPE);
 381     free_cmdtable(HASH_CODE);
 382     if(cerr->num > 0) {
 383         stat = 1;
 384     }
 385     freecerr();
 386     return stat;
 387 }
 388 
 389 void monitor()
 390 {
 391     char *buf = NULL;
 392     MONCMDLINE *moncmdl = NULL;
 393     MONCMDTYPE cmdtype = MONREPEAT;
 394 
 395     do {
 396         fprintf(stdout, "%s ", monitor_prompt);
 397         buf = malloc_chk(MONINSIZE + 1, "monitor.buf");
 398         fgets(buf, MONINSIZE, stdin);
 399         if(!buf[0]) {
 400             cmdtype = MONQUIT;
 401         }
 402         strip_end(buf);        /* 文字列末尾の改行と空白を削除 */
 403         fprintf(stdout, "%s\n", buf);
 404         if((moncmdl = monlinetok(buf)) != NULL) {
 405             cmdtype = monitorcmd(moncmdl->cmd, moncmdl->args);
 406             free_moncmdline(moncmdl);
 407         }
 408         FREE(buf);
 409         if(cmdtype == MONQUIT) {
 410             exit(monquit());
 411         }
 412     } while(cmdtype == MONREPEAT);
 413 }

/* [<][>][^][v][top][bottom][index][help] */