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

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