ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/mon/src/mon.cpp
Revision: 1.24
Committed: 2004-02-12T17:14:36Z (20 years, 3 months ago) by cebix
Branch: MAIN
Changes since 1.23: +1 -1 lines
Log Message:
removed restriction to 256 bytes for commands that use byte_string() (modify,
fill, hunt)

File Contents

# User Rev Content
1 cebix 1.1 /*
2 cebix 1.14 * mon.cpp - cxmon main program
3 cebix 1.1 *
4 cebix 1.22 * cxmon (C) 1997-2003 Christian Bauer, Marc Hellwig
5 cebix 1.2 *
6     * This program is free software; you can redistribute it and/or modify
7     * it under the terms of the GNU General Public License as published by
8     * the Free Software Foundation; either version 2 of the License, or
9     * (at your option) any later version.
10     *
11     * This program is distributed in the hope that it will be useful,
12     * but WITHOUT ANY WARRANTY; without even the implied warranty of
13     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14     * GNU General Public License for more details.
15     *
16     * You should have received a copy of the GNU General Public License
17     * along with this program; if not, write to the Free Software
18     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 cebix 1.1 */
20    
21 cebix 1.2 #include "sysdeps.h"
22    
23 cebix 1.5 #include <stdio.h>
24     #include <stdlib.h>
25     #include <signal.h>
26     #include <ctype.h>
27 cebix 1.15 #include <string>
28     #include <map>
29 cebix 1.5
30 cebix 1.9 #if defined(HAVE_READLINE_H)
31     extern "C" {
32     #include <readline.h>
33     }
34     #elif defined(HAVE_READLINE_READLINE_H)
35 cebix 1.2 extern "C" {
36     #include <readline/readline.h>
37     }
38     #endif
39 cebix 1.1
40 cebix 1.9 #if defined(HAVE_HISTORY_H)
41     extern "C" {
42     #include <history.h>
43     }
44     #elif defined(HAVE_READLINE_HISTORY_H)
45 cebix 1.1 extern "C" {
46 cebix 1.2 #include <readline/history.h>
47 cebix 1.1 }
48 cebix 1.2 #endif
49 cebix 1.1
50     #include "mon.h"
51     #include "mon_cmd.h"
52 cebix 1.15 #include "mon_lowmem.h"
53 cebix 1.1
54 hellwig 1.8 #ifndef VERSION
55 cebix 1.19 #define VERSION "3"
56 hellwig 1.8 #endif
57    
58 cebix 1.1
59     // Buffer we're operating on
60     bool mon_use_real_mem = false;
61     uint32 mon_mem_size;
62     static uint8 *mem;
63    
64    
65     // Streams for input, output and error messages
66     FILE *monin, *monout, *monerr;
67    
68     // Input line
69 cebix 1.23 static char *input;
70 cebix 1.1 static char *in_ptr;
71     char *mon_args_ptr;
72    
73     // Current address, value of '.' in expressions
74 gbeauche 1.18 uintptr mon_dot_address;
75 cebix 1.1
76     // Current value of ':' in expression
77     static uint32 colon_value;
78    
79    
80     // Scanner variables
81 cebix 1.23 enum Token mon_token; // Last token read
82     uintptr mon_number; // Contains the number if mon_token==T_NUMBER
83     char *mon_string; // Contains the string if mon_token==T_STRING
84     char *mon_name; // Contains the variable name if mon_token==T_NAME
85 cebix 1.1
86    
87     // List of installed commands
88     struct CmdSpec {
89 cebix 1.23 const char *name; // Name of command
90     void (*func)(); // Function that executes this command
91 cebix 1.1 };
92    
93 cebix 1.23 static CmdSpec *cmds; // Array of CmdSpecs
94     static int num_cmds; // Number of installed commands
95     static char *cmd_help; // Help text for commands
96 cebix 1.1
97    
98     // List of variables
99 gbeauche 1.18 typedef std::map<std::string, uintptr> var_map;
100 cebix 1.15 static var_map vars;
101 cebix 1.1
102    
103     // Prototypes
104 cebix 1.23 static void init_abort();
105     static void exit_abort();
106 cebix 1.1
107     static void read_line(char *prompt); // Scanner
108 cebix 1.23 static char get_char();
109 cebix 1.1 static void put_back(char c);
110 gbeauche 1.18 static enum Token get_hex_number(uintptr &i);
111     static enum Token get_dec_number(uintptr &i);
112     static enum Token get_char_number(uintptr &i);
113 cebix 1.23 static enum Token get_string(char *&str);
114     static enum Token get_hex_or_name(uintptr &i, char *&name);
115 cebix 1.1
116 gbeauche 1.18 static bool eor_expr(uintptr *number); // Parser
117     static bool and_expr(uintptr *number);
118     static bool shift_expr(uintptr *number);
119     static bool add_expr(uintptr *number);
120     static bool mul_expr(uintptr *number);
121     static bool factor(uintptr *number);
122 cebix 1.1
123    
124     /*
125     * Add command to mon
126     */
127    
128 cebix 1.23 void mon_add_command(const char *name, void (*func)(), const char *help_text)
129 cebix 1.1 {
130     num_cmds++;
131     if (cmds)
132     cmds = (CmdSpec *)realloc(cmds, num_cmds * sizeof(CmdSpec));
133     else
134     cmds = (CmdSpec *)malloc(sizeof(CmdSpec));
135     cmds[num_cmds - 1].name = name;
136     cmds[num_cmds - 1].func = func;
137     if (help_text) {
138     if (cmd_help) {
139     cmd_help = (char *)realloc(cmd_help, strlen(cmd_help) + strlen(help_text) + 1);
140     strcat(cmd_help, help_text);
141     } else
142     cmd_help = strdup(help_text);
143     }
144     }
145    
146    
147     /*
148     * Print error message
149     */
150    
151     void mon_error(const char *s)
152     {
153     fprintf(monerr, "*** %s\n", s);
154     }
155    
156    
157     /*
158     * CTRL-C pressed?
159     */
160    
161     static bool was_aborted;
162     static struct sigaction my_sa;
163    
164     #ifdef __BEOS__
165     static void handle_abort(int sig, void *arg, vregs *r)
166     #else
167     static void handle_abort(int sig)
168     #endif
169     {
170     was_aborted = true;
171     }
172    
173 cebix 1.23 static void init_abort()
174 cebix 1.1 {
175     was_aborted = false;
176     sigemptyset(&my_sa.sa_mask);
177     #ifdef __BEOS__
178     my_sa.sa_handler = (__signal_func_ptr)handle_abort;
179     my_sa.sa_userdata = 0;
180     #else
181     my_sa.sa_handler = handle_abort;
182     #endif
183     my_sa.sa_flags = 0;
184     sigaction(SIGINT, &my_sa, NULL);
185     }
186    
187 cebix 1.23 static void exit_abort()
188 cebix 1.1 {
189     my_sa.sa_handler = SIG_DFL;
190     sigaction(SIGINT, &my_sa, NULL);
191     }
192    
193 cebix 1.23 bool mon_aborted()
194 cebix 1.1 {
195     bool ret = was_aborted;
196     was_aborted = false;
197     return ret;
198     }
199    
200    
201     /*
202     * Access to buffer
203     */
204    
205 gbeauche 1.18 uint32 (*mon_read_byte)(uintptr adr);
206 cebix 1.5
207 gbeauche 1.18 uint32 mon_read_byte_buffer(uintptr adr)
208 cebix 1.5 {
209     return mem[adr % mon_mem_size];
210     }
211    
212 gbeauche 1.18 uint32 mon_read_byte_real(uintptr adr)
213 cebix 1.5 {
214     return *(uint8 *)adr;
215     }
216    
217 gbeauche 1.18 void (*mon_write_byte)(uintptr adr, uint32 b);
218 cebix 1.5
219 gbeauche 1.18 void mon_write_byte_buffer(uintptr adr, uint32 b)
220 cebix 1.1 {
221 cebix 1.5 mem[adr % mon_mem_size] = b;
222 cebix 1.1 }
223    
224 gbeauche 1.18 void mon_write_byte_real(uintptr adr, uint32 b)
225 cebix 1.1 {
226 cebix 1.5 *(uint8 *)adr = b;
227 cebix 1.1 }
228    
229 gbeauche 1.18 uint32 mon_read_half(uintptr adr)
230 cebix 1.1 {
231 cebix 1.5 return (mon_read_byte(adr) << 8) | mon_read_byte(adr+1);
232 cebix 1.1 }
233    
234 gbeauche 1.18 void mon_write_half(uintptr adr, uint32 w)
235 cebix 1.1 {
236 cebix 1.5 mon_write_byte(adr, w >> 8);
237     mon_write_byte(adr+1, w);
238 cebix 1.1 }
239    
240 gbeauche 1.18 uint32 mon_read_word(uintptr adr)
241 cebix 1.1 {
242 cebix 1.5 return (mon_read_byte(adr) << 24) | (mon_read_byte(adr+1) << 16) | (mon_read_byte(adr+2) << 8) | mon_read_byte(adr+3);
243 cebix 1.1 }
244    
245 gbeauche 1.18 void mon_write_word(uintptr adr, uint32 l)
246 cebix 1.1 {
247 cebix 1.5 mon_write_byte(adr, l >> 24);
248     mon_write_byte(adr+1, l >> 16);
249     mon_write_byte(adr+2, l >> 8);
250     mon_write_byte(adr+3, l);
251 cebix 1.1 }
252    
253    
254     /*
255     * Read a line from the keyboard
256     */
257    
258     static void read_line(char *prompt)
259     {
260 cebix 1.4 #ifdef HAVE_LIBREADLINE
261 cebix 1.1 static char *line_read = NULL;
262    
263 cebix 1.23 if (input)
264     free(input);
265     input = readline(prompt);
266    
267     if (input) {
268     if (*input)
269     add_history(input);
270 cebix 1.21 } else {
271     // EOF, quit cxmon
272 cebix 1.23 input = (char *)malloc(2);
273 cebix 1.21 input[0] = 'x';
274     input[1] = 0;
275 cebix 1.23 fprintf(monout, "x\n");
276 cebix 1.21 }
277 cebix 1.23
278     in_ptr = input;
279 cebix 1.4 #else
280 cebix 1.24 static const unsigned INPUT_LENGTH = 256;
281 cebix 1.23 if (!input)
282     input = (char *)malloc(INPUT_LENGTH);
283 cebix 1.4 fprintf(monout, prompt);
284     fflush(monout);
285     fgets(in_ptr = input, INPUT_LENGTH, monin);
286     char *s = strchr(input, '\n');
287     if (s != NULL)
288     *s = 0;
289     #endif
290 cebix 1.1 }
291    
292    
293     /*
294     * Read a character from the input line
295     */
296    
297 cebix 1.23 static char get_char()
298 cebix 1.1 {
299     return *in_ptr++;
300     }
301    
302    
303     /*
304     * Stuff back a character into the input line
305     */
306    
307     static void put_back(char c)
308     {
309     *(--in_ptr) = c;
310     }
311    
312    
313     /*
314     * Scanner: Get a token from the input line
315     */
316    
317 cebix 1.23 enum Token mon_get_token()
318 cebix 1.1 {
319 cebix 1.23 char c = get_char();
320 cebix 1.1
321     // Skip spaces
322 cebix 1.23 while (isspace(c))
323     c = get_char();
324 cebix 1.1
325     switch (c) {
326     case 0:
327     return mon_token = T_END;
328     case '(':
329     return mon_token = T_LPAREN;
330     case ')':
331     return mon_token = T_RPAREN;
332     case '.':
333     return mon_token = T_DOT;
334     case ':':
335     return mon_token = T_COLON;
336     case ',':
337     return mon_token = T_COMMA;
338     case '+':
339     return mon_token = T_PLUS;
340     case '-':
341     return mon_token = T_MINUS;
342     case '*':
343     return mon_token = T_MUL;
344     case '/':
345     return mon_token = T_DIV;
346     case '%':
347     return mon_token = T_MOD;
348     case '&':
349     return mon_token = T_AND;
350     case '|':
351     return mon_token = T_OR;
352     case '^':
353     return mon_token = T_EOR;
354     case '<':
355     if (get_char() == '<')
356     return mon_token = T_SHIFTL;
357     else {
358     mon_error("Unrecognized token");
359     return mon_token = T_NULL;
360     }
361     case '>':
362     if (get_char() == '>')
363     return mon_token = T_SHIFTR;
364     else {
365     mon_error("Unrecognized token");
366     return mon_token = T_NULL;
367     }
368     case '~':
369     return mon_token = T_NOT;
370     case '=':
371     return mon_token = T_ASSIGN;
372    
373     case '$':
374     if ((mon_token = get_hex_number(mon_number)) == T_NULL)
375     mon_error("'$' must be followed by hexadecimal number");
376     return mon_token;
377     case '_':
378     if ((mon_token = get_dec_number(mon_number)) == T_NULL)
379     mon_error("'_' must be followed by decimal number");
380     return mon_token;
381     case '\'':
382     return mon_token = get_char_number(mon_number);
383     case '"':
384     return mon_token = get_string(mon_string);
385    
386     default:
387     if (isalnum(c)) {
388     put_back(c);
389     return mon_token = get_hex_or_name(mon_number, mon_name);
390     }
391     mon_error("Unrecognized token");
392     return mon_token = T_NULL;
393     }
394     }
395    
396 gbeauche 1.18 static enum Token get_hex_number(uintptr &i)
397 cebix 1.1 {
398     char c = get_char();
399    
400     i = 0;
401     if (!isxdigit(c))
402     return T_NULL;
403    
404     do {
405 cebix 1.16 c = tolower(c);
406 cebix 1.1 if (c < 'a')
407     i = (i << 4) + (c - '0');
408     else
409     i = (i << 4) + (c - 'a' + 10);
410     c = get_char();
411     } while (isxdigit(c));
412    
413     if (isalnum(c))
414     return T_NULL;
415     else {
416     put_back(c);
417     return T_NUMBER;
418     }
419     }
420    
421 gbeauche 1.18 static enum Token get_dec_number(uintptr &i)
422 cebix 1.1 {
423     char c = get_char();
424    
425     i = 0;
426     if (!isdigit(c))
427     return T_NULL;
428    
429     do {
430     i = (i * 10) + (c - '0');
431     c = get_char();
432     } while (isdigit(c));
433    
434     if (isalnum(c))
435     return T_NULL;
436     else {
437     put_back(c);
438     return T_NUMBER;
439     }
440     }
441    
442 gbeauche 1.18 static enum Token get_char_number(uintptr &i)
443 cebix 1.1 {
444     char c;
445    
446     i = 0;
447     while ((c = get_char()) != 0) {
448     if (c == '\'')
449     return T_NUMBER;
450     i = (i << 8) + (uint8)c;
451     }
452    
453     mon_error("Unterminated character constant");
454     return T_NULL;
455     }
456    
457 cebix 1.23 static enum Token get_string(char *&str)
458 cebix 1.1 {
459 cebix 1.23 // Remember start of string
460     char *old_in_ptr = in_ptr;
461    
462     // Determine string length
463 cebix 1.1 char c;
464 cebix 1.23 unsigned n = 0;
465 cebix 1.1 while ((c = get_char()) != 0) {
466 cebix 1.23 n++;
467     if (c == '"')
468     break;
469     }
470     if (c == 0) {
471     mon_error("Unterminated string");
472     return T_NULL;
473 cebix 1.1 }
474    
475 cebix 1.23 // Allocate new buffer (n: size needed including terminating 0)
476     str = (char *)realloc(str, n);
477    
478     // Copy string to buffer
479     char *p = str;
480     in_ptr = old_in_ptr;
481     while (--n)
482     *p++ = get_char();
483     *p++ = 0;
484     get_char(); // skip closing '"'
485     return T_STRING;
486 cebix 1.1 }
487    
488 cebix 1.23 static enum Token get_hex_or_name(uintptr &i, char *&name)
489 cebix 1.1 {
490 cebix 1.23 // Remember start of token
491 cebix 1.1 char *old_in_ptr = in_ptr;
492    
493     // Try hex number first
494     if (get_hex_number(i) == T_NUMBER)
495     return T_NUMBER;
496    
497 cebix 1.23 // Not a hex number, must be a variable name; determine its length
498 cebix 1.1 in_ptr = old_in_ptr;
499 cebix 1.23 char c = get_char();
500     unsigned n = 1;
501 cebix 1.1 do {
502 cebix 1.23 n++;
503 cebix 1.1 c = get_char();
504     } while (isalnum(c));
505    
506 cebix 1.23 // Allocate new buffer (n: size needed including terminating 0)
507     name = (char *)realloc(name, n);
508    
509     // Copy name to buffer
510     in_ptr = old_in_ptr;
511     char *p = name;
512     while (--n)
513     *p++ = get_char();
514     *p = 0;
515 cebix 1.1 return T_NAME;
516     }
517    
518    
519     /*
520     * expression = eor_expr {OR eor_expr}
521     * true: OK, false: Error
522     */
523    
524 gbeauche 1.18 bool mon_expression(uintptr *number)
525 cebix 1.1 {
526 gbeauche 1.18 uintptr accu, expr;
527 cebix 1.1
528     if (!eor_expr(&accu))
529     return false;
530    
531     for (;;)
532     switch (mon_token) {
533     case T_OR:
534     mon_get_token();
535     if (!eor_expr(&expr))
536     return false;
537     accu |= expr;
538     break;
539    
540     default:
541     *number = accu;
542     return true;
543     }
544     }
545    
546    
547     /*
548     * eor_expr = and_expr {EOR and_expr}
549     * true: OK, false: Error
550     */
551    
552 gbeauche 1.18 static bool eor_expr(uintptr *number)
553 cebix 1.1 {
554 gbeauche 1.18 uintptr accu, expr;
555 cebix 1.1
556     if (!and_expr(&accu))
557     return false;
558    
559     for (;;)
560     switch (mon_token) {
561     case T_EOR:
562     mon_get_token();
563     if (!and_expr(&expr))
564     return false;
565     accu ^= expr;
566     break;
567    
568     default:
569     *number = accu;
570     return true;
571     }
572     }
573    
574    
575     /*
576     * and_expr = shift_expr {AND shift_expr}
577     * true: OK, false: Error
578     */
579    
580 gbeauche 1.18 static bool and_expr(uintptr *number)
581 cebix 1.1 {
582 gbeauche 1.18 uintptr accu, expr;
583 cebix 1.1
584     if (!shift_expr(&accu))
585     return false;
586    
587     for (;;)
588     switch (mon_token) {
589     case T_AND:
590     mon_get_token();
591     if (!shift_expr(&expr))
592     return false;
593     accu &= expr;
594     break;
595    
596     default:
597     *number = accu;
598     return true;
599     }
600     }
601    
602    
603     /*
604     * shift_expr = add_expr {(SHIFTL | SHIFTR) add_expr}
605     * true: OK, false: Error
606     */
607    
608 gbeauche 1.18 static bool shift_expr(uintptr *number)
609 cebix 1.1 {
610 gbeauche 1.18 uintptr accu, expr;
611 cebix 1.1
612     if (!add_expr(&accu))
613     return false;
614    
615     for (;;)
616     switch (mon_token) {
617     case T_SHIFTL:
618     mon_get_token();
619     if (!add_expr(&expr))
620     return false;
621     accu <<= expr;
622     break;
623    
624     case T_SHIFTR:
625     mon_get_token();
626     if (!add_expr(&expr))
627     return false;
628     accu >>= expr;
629     break;
630    
631     default:
632     *number = accu;
633     return true;
634     }
635     }
636    
637    
638     /*
639     * add_expr = mul_expr {(PLUS | MINUS) mul_expr}
640     * true: OK, false: Error
641     */
642    
643 gbeauche 1.18 static bool add_expr(uintptr *number)
644 cebix 1.1 {
645 gbeauche 1.18 uintptr accu, expr;
646 cebix 1.1
647     if (!mul_expr(&accu))
648     return false;
649    
650     for (;;)
651     switch (mon_token) {
652     case T_PLUS:
653     mon_get_token();
654     if (!mul_expr(&expr))
655     return false;
656     accu += expr;
657     break;
658    
659     case T_MINUS:
660     mon_get_token();
661     if (!mul_expr(&expr))
662     return false;
663     accu -= expr;
664     break;
665    
666     default:
667     *number = accu;
668     return true;
669     }
670     }
671    
672    
673     /*
674     * mul_expr = factor {(MUL | DIV | MOD) factor}
675     * true: OK, false: Error
676     */
677    
678 gbeauche 1.18 static bool mul_expr(uintptr *number)
679 cebix 1.1 {
680 gbeauche 1.18 uintptr accu, fact;
681 cebix 1.1
682     if (!factor(&accu))
683     return false;
684    
685     for (;;)
686     switch (mon_token) {
687     case T_MUL:
688     mon_get_token();
689     if (!factor(&fact))
690     return false;
691     accu *= fact;
692     break;
693    
694     case T_DIV:
695     mon_get_token();
696     if (!factor(&fact))
697     return false;
698     if (fact == 0) {
699     mon_error("Division by 0");
700     return false;
701     }
702     accu /= fact;
703     break;
704    
705     case T_MOD:
706     mon_get_token();
707     if (!factor(&fact))
708     return false;
709     if (fact == 0) {
710     mon_error("Division by 0");
711     return false;
712     }
713     accu %= fact;
714     break;
715    
716     default:
717     *number = accu;
718     return true;
719     }
720     }
721    
722    
723     /*
724     * factor = NUMBER | NAME | DOT | COLON | (PLUS | MINUS | NOT) factor | LPAREN expression RPAREN
725     * true: OK, false: Error
726     */
727    
728 gbeauche 1.18 static bool factor(uintptr *number)
729 cebix 1.1 {
730     switch (mon_token) {
731     case T_NUMBER:
732     *number = mon_number;
733     mon_get_token();
734     return true;
735    
736     case T_NAME:{
737 cebix 1.15 var_map::const_iterator v = vars.find(mon_name);
738     if (v == vars.end())
739     return false;
740     else {
741     *number = v->second;
742 cebix 1.1 mon_get_token();
743     return true;
744 cebix 1.15 }
745 cebix 1.1 }
746    
747     case T_DOT:
748     *number = mon_dot_address;
749     mon_get_token();
750     return true;
751    
752     case T_COLON:
753     *number = colon_value;
754     mon_get_token();
755     return true;
756    
757     case T_PLUS:
758     mon_get_token();
759     return factor(number);
760    
761     case T_MINUS:
762     mon_get_token();
763     if (factor(number)) {
764     *number = -*number;
765     return true;
766     } else
767     return false;
768    
769     case T_NOT:
770     mon_get_token();
771     if (factor(number)) {
772     *number = ~*number;
773     return true;
774     } else
775     return false;
776    
777     case T_LPAREN:
778     mon_get_token();
779     if (mon_expression(number))
780     if (mon_token == T_RPAREN) {
781     mon_get_token();
782     return true;
783     } else {
784     mon_error("Missing ')'");
785     return false;
786     }
787     else {
788     mon_error("Error in expression");
789     return false;
790     }
791    
792     case T_END:
793     mon_error("Required argument missing");
794     return false;
795    
796     default:
797     mon_error("'(' or number expected");
798     return false;
799     }
800     }
801    
802    
803     /*
804     * Set/clear/show variables
805     * set [var[=value]]
806     */
807    
808 cebix 1.23 static void set_var()
809 cebix 1.1 {
810     if (mon_token == T_END) {
811    
812     // Show all variables
813 cebix 1.15 if (vars.empty())
814 cebix 1.1 fprintf(monout, "No variables defined\n");
815 cebix 1.15 else {
816     var_map::const_iterator v = vars.begin(), end = vars.end();
817     for (v=vars.begin(); v!=end; ++v)
818     fprintf(monout, "%s = %08x\n", v->first.c_str(), v->second);
819     }
820 cebix 1.1
821     } else if (mon_token == T_NAME) {
822 gbeauche 1.17 std::string var_name = mon_name;
823 cebix 1.1 mon_get_token();
824     if (mon_token == T_ASSIGN) {
825    
826     // Set variable
827 gbeauche 1.18 uintptr value;
828 cebix 1.1 mon_get_token();
829     if (!mon_expression(&value))
830     return;
831     if (mon_token != T_END) {
832     mon_error("Too many arguments");
833     return;
834     }
835 cebix 1.15 vars[var_name] = value;
836 cebix 1.1
837     } else if (mon_token == T_END) {
838    
839     // Clear variable
840 cebix 1.15 vars.erase(var_name);
841 cebix 1.1
842     } else
843     mon_error("'=' expected");
844     } else
845     mon_error("Variable name expected");
846     }
847    
848    
849     /*
850     * Clear all variables
851     * cv
852     */
853    
854 cebix 1.23 static void clear_vars()
855 cebix 1.1 {
856 cebix 1.15 vars.clear();
857 cebix 1.1 }
858    
859    
860     /*
861     * Display help
862     * h
863     */
864    
865 cebix 1.23 static void help_or_hunt()
866 cebix 1.1 {
867     if (mon_token != T_END) {
868     hunt();
869     return;
870     }
871     fprintf(monout, "x Quit mon\n"
872     "h This help text\n");
873     fprintf(monout, cmd_help);
874     }
875    
876    
877     /*
878     * Display command list
879     * ??
880     */
881    
882 cebix 1.23 static void mon_cmd_list()
883 cebix 1.1 {
884     for (int i=0; i<num_cmds; i++)
885     fprintf(monout, "%s ", cmds[i].name);
886     fprintf(monout, "\n");
887     }
888    
889    
890     /*
891     * Reallocate buffer
892     * @ [size]
893     */
894    
895 cebix 1.23 static void reallocate()
896 cebix 1.1 {
897 gbeauche 1.18 uintptr size;
898 cebix 1.1
899     if (mon_use_real_mem) {
900     fprintf(monerr, "Cannot reallocate buffer in real mode\n");
901     return;
902     }
903    
904     if (mon_token == T_END) {
905 cebix 1.3 fprintf(monerr, "Buffer size: %08x bytes\n", mon_mem_size);
906 cebix 1.1 return;
907     }
908    
909     if (!mon_expression(&size))
910     return;
911     if (mon_token != T_END) {
912     mon_error("Too many arguments");
913     return;
914     }
915    
916     if ((mem = (uint8 *)realloc(mem, size)) != NULL)
917 cebix 1.3 fprintf(monerr, "Buffer size: %08x bytes\n", mon_mem_size = size);
918 cebix 1.1 else
919     fprintf(monerr, "Unable to reallocate buffer\n");
920     }
921    
922    
923     /*
924     * Apply expression to memory
925     * y[b|h|w] start end expression
926     */
927    
928     static void apply(int size)
929     {
930 gbeauche 1.18 uintptr adr, end_adr, value;
931 cebix 1.1 char c;
932    
933     if (!mon_expression(&adr))
934     return;
935     if (!mon_expression(&end_adr))
936     return;
937     if (!mon_expression(&value))
938     return;
939     if (mon_token != T_END) {
940     mon_error("Too many arguments");
941     return;
942     }
943    
944 gbeauche 1.18 uint32 (*read_func)(uintptr adr);
945     void (*write_func)(uintptr adr, uint32 val);
946 cebix 1.1 switch (size) {
947     case 1:
948     read_func = mon_read_byte;
949     write_func = mon_write_byte;
950     break;
951     case 2:
952     read_func = mon_read_half;
953     write_func = mon_write_half;
954     break;
955     case 4:
956     read_func = mon_read_word;
957     write_func = mon_write_word;
958     break;
959 cebix 1.3 default:
960     abort();
961     break;
962 cebix 1.1 }
963    
964     while (adr<=end_adr) {
965     colon_value = read_func(adr);
966     mon_dot_address = adr;
967    
968     in_ptr = input;
969     while ((c = get_char()) == ' ') ;
970     while ((c = get_char()) != ' ') ;
971     while ((c = get_char()) == ' ') ;
972     put_back(c);
973     mon_get_token();
974     mon_expression(&value); // Skip start address
975     mon_expression(&value); // Skip end address
976     mon_expression(&value);
977    
978     write_func(adr, value);
979     adr += size;
980     }
981    
982     mon_dot_address = adr;
983     }
984    
985 cebix 1.23 static void apply_byte()
986 cebix 1.1 {
987     apply(1);
988     }
989    
990 cebix 1.23 static void apply_half()
991 cebix 1.1 {
992     apply(2);
993     }
994    
995 cebix 1.23 static void apply_word()
996 cebix 1.1 {
997     apply(4);
998     }
999    
1000    
1001     /*
1002     * Execute command via system() (for ls, rm, etc.)
1003     */
1004    
1005 cebix 1.23 static void mon_exec()
1006 cebix 1.1 {
1007     system(input);
1008     }
1009    
1010    
1011     /*
1012     * Change current directory
1013     */
1014    
1015 cebix 1.23 void mon_change_dir()
1016 cebix 1.1 {
1017     in_ptr = input;
1018 cebix 1.23 char c = get_char();
1019     while (isspace(c))
1020     c = get_char();
1021     while (isgraph(c))
1022     c = get_char();
1023     while (isspace(c))
1024     c = get_char();
1025 cebix 1.1 put_back(c);
1026     if (chdir(in_ptr) != 0)
1027     mon_error("Cannot change directory");
1028     }
1029    
1030    
1031     /*
1032     * Initialize mon
1033     */
1034    
1035 cebix 1.23 void mon_init()
1036 cebix 1.1 {
1037     cmds = NULL;
1038     num_cmds = 0;
1039     cmd_help = NULL;
1040    
1041 cebix 1.12 mon_add_command("??", mon_cmd_list, "?? Show list of commands\n");
1042     mon_add_command("ver", version, "ver Show version\n");
1043     mon_add_command("?", print_expr, "? expression Calculate expression\n");
1044     mon_add_command("@", reallocate, "@ [size] Reallocate buffer\n");
1045     mon_add_command("i", ascii_dump, "i [start [end]] ASCII memory dump\n");
1046     mon_add_command("m", memory_dump, "m [start [end]] Hex/ASCII memory dump\n");
1047     mon_add_command("b", binary_dump, "b [start [end]] Binary memory dump\n");
1048     mon_add_command("d", disassemble_ppc, "d [start [end]] Disassemble PowerPC code\n");
1049     mon_add_command("d65", disassemble_6502, "d65 [start [end]] Disassemble 6502 code\n");
1050     mon_add_command("d68", disassemble_680x0, "d68 [start [end]] Disassemble 680x0 code\n");
1051 cebix 1.14 mon_add_command("d80", disassemble_z80, "d80 [start [end]] Disassemble Z80 code\n");
1052 cebix 1.12 mon_add_command("d86", disassemble_80x86_32, "d86 [start [end]] Disassemble 80x86 (32-bit) code\n");
1053 cebix 1.13 mon_add_command("d8086", disassemble_80x86_16, "d8086 [start [end]] Disassemble 80x86 (16-bit) code\n");
1054 gbeauche 1.20 mon_add_command("d8664", disassemble_x86_64, "d8664 [start [end]] Disassemble x86-64 code\n");
1055 cebix 1.12 mon_add_command(":", modify, ": start string Modify memory\n");
1056     mon_add_command("f", fill, "f start end string Fill memory\n");
1057     mon_add_command("y", apply_byte, "y[b|h|w] start end expr Apply expression to memory\n");
1058 cebix 1.1 mon_add_command("yb", apply_byte, NULL);
1059     mon_add_command("yh", apply_half, NULL);
1060     mon_add_command("yw", apply_word, NULL);
1061 cebix 1.12 mon_add_command("t", transfer, "t start end dest Transfer memory\n");
1062     mon_add_command("c", compare, "c start end dest Compare memory\n");
1063     mon_add_command("h", help_or_hunt, "h start end string Search for byte string\n");
1064     mon_add_command("\\", shell_command, "\\ \"command\" Execute shell command\n");
1065     mon_add_command("ls", mon_exec, "ls [args] List directory contents\n");
1066     mon_add_command("rm", mon_exec, "rm [args] Remove file(s)\n");
1067     mon_add_command("cp", mon_exec, "cp [args] Copy file(s)\n");
1068     mon_add_command("mv", mon_exec, "mv [args] Move file(s)\n");
1069     mon_add_command("cd", mon_change_dir, "cd directory Change current directory\n");
1070     mon_add_command("o", redir_output, "o [\"file\"] Redirect output\n");
1071     mon_add_command("[", load_data, "[ start \"file\" Load data from file\n");
1072     mon_add_command("]", save_data, "] start size \"file\" Save data to file\n");
1073     mon_add_command("set", set_var, "set [var[=value]] Set/clear/show variables\n");
1074     mon_add_command("cv", clear_vars, "cv Clear all variables\n");
1075 cebix 1.5
1076     mon_read_byte = NULL;
1077     mon_write_byte = NULL;
1078 cebix 1.23
1079     input = NULL;
1080     mon_string = NULL;
1081     mon_name = NULL;
1082 cebix 1.1 }
1083    
1084    
1085     /*
1086     * Deinitialize mon
1087     */
1088    
1089 cebix 1.23 void mon_exit()
1090 cebix 1.1 {
1091 cebix 1.23 if (cmds) {
1092     free(cmds);
1093     cmds = NULL;
1094     }
1095 cebix 1.1 num_cmds = 0;
1096     cmd_help = NULL;
1097 cebix 1.23
1098     if (input) {
1099     free(input);
1100     input = NULL;
1101     }
1102     if (mon_string) {
1103     free(mon_string);
1104     mon_string = NULL;
1105     }
1106     if (mon_name) {
1107     free(mon_name);
1108     mon_name = NULL;
1109     }
1110 cebix 1.1 }
1111    
1112    
1113     /*
1114     * Main function, read-execute loop
1115     */
1116    
1117     void mon(int argc, char **argv)
1118     {
1119     bool done = false, interactive = true;
1120    
1121     // Setup input/output streams
1122     monin = stdin;
1123     monout = stdout;
1124     monerr = stdout;
1125    
1126 cebix 1.11 // Make argc/argv point to the actual arguments
1127 cebix 1.15 const char *prg_name = argv[0];
1128 cebix 1.11 if (argc)
1129     argc--; argv++;
1130    
1131     // Parse arguments
1132     mon_macos_mode = false;
1133     mon_use_real_mem = false;
1134     while (argc > 0) {
1135 cebix 1.15 if (strcmp(argv[0], "-h") == 0 || strcmp(argv[0], "--help") == 0) {
1136     printf("Usage: %s [-m] [-r] [command...]\n", prg_name);
1137     exit(0);
1138     } else if (strcmp(argv[0], "-m") == 0)
1139 cebix 1.11 mon_macos_mode = true;
1140     else if (strcmp(argv[0], "-r") == 0)
1141 cebix 1.1 mon_use_real_mem = true;
1142 cebix 1.11 else
1143     break;
1144     argc--; argv++;
1145 cebix 1.1 }
1146 cebix 1.11 interactive = (argc == 0);
1147 cebix 1.1
1148 cebix 1.5 // Set up memory access functions if not supplied by the user
1149     if (mon_read_byte == NULL) {
1150     if (mon_use_real_mem)
1151     mon_read_byte = mon_read_byte_real;
1152     else
1153     mon_read_byte = mon_read_byte_buffer;
1154     }
1155     if (mon_write_byte == NULL) {
1156     if (mon_use_real_mem)
1157     mon_write_byte = mon_write_byte_real;
1158     else
1159     mon_write_byte = mon_write_byte_buffer;
1160     }
1161    
1162 cebix 1.1 // Allocate buffer
1163     if (!mon_use_real_mem) {
1164     mon_mem_size = 0x100000;
1165     mem = (uint8 *)malloc(mon_mem_size);
1166    
1167     // Print banner
1168     if (interactive)
1169 cebix 1.14 fprintf(monerr, "\n *** cxmon V" VERSION " by Christian Bauer and Marc Hellwig ***\n"
1170     " *** Press 'h' for help ***\n\n");
1171 cebix 1.15 }
1172    
1173     // Clear variables
1174     vars.clear();
1175    
1176     // In MacOS mode, pull in the lowmem globals as variables
1177     if (mon_macos_mode) {
1178     const lowmem_info *l = lowmem;
1179     while (l->name) {
1180     vars[l->name] = l->addr;
1181     l++;
1182     }
1183 cebix 1.1 }
1184    
1185     init_abort();
1186    
1187     // Read and parse command line
1188 cebix 1.23 char *cmd = NULL;
1189 cebix 1.1 while (!done) {
1190     if (interactive) {
1191     char prompt[16];
1192 gbeauche 1.18 sprintf(prompt, "[%0*lx]-> ", 2 * sizeof(mon_dot_address), mon_dot_address);
1193 cebix 1.1 read_line(prompt);
1194 cebix 1.23 if (!input) {
1195     done = true;
1196     continue;
1197     }
1198 cebix 1.1 } else {
1199     if (argc == 0) {
1200     done = true;
1201     break;
1202     } else {
1203 cebix 1.23 unsigned n = strlen(argv[0]) + 1;
1204     input = (char *)realloc(input, n);
1205     strcpy(in_ptr = input, argv[0]);
1206 cebix 1.1 argc--;
1207     argv++;
1208     }
1209     }
1210    
1211     // Skip leading spaces
1212 cebix 1.23 char c = get_char();
1213     while (isspace(c))
1214     c = get_char();
1215     put_back(c);
1216     if (!c)
1217     continue; // blank line
1218 cebix 1.1
1219     // Read command word
1220 cebix 1.23 char *p = in_ptr;
1221     while (isgraph(c))
1222 cebix 1.1 c = get_char();
1223     put_back(c);
1224 cebix 1.23 unsigned n = in_ptr - p;
1225     cmd = (char *)realloc(cmd, n + 1);
1226     memcpy(cmd, p, n);
1227     cmd[n] = 0;
1228 cebix 1.1
1229     // Execute command
1230     if (strcmp(cmd, "x") == 0) { // Exit
1231     done = true;
1232     continue;
1233     }
1234     for (int i=0; i<num_cmds; i++) {
1235     if (strcmp(cmd, cmds[i].name) == 0) {
1236     mon_get_token();
1237     cmds[i].func();
1238     goto cmd_done;
1239     }
1240     }
1241     mon_error("Unknown command");
1242     cmd_done: ;
1243     }
1244 cebix 1.23
1245     if (cmd)
1246     free(cmd);
1247 cebix 1.1
1248     exit_abort();
1249    
1250     // Free buffer
1251     if (!mon_use_real_mem)
1252     free(mem);
1253    
1254     // Close output file if redirected
1255     if (monout != monerr)
1256     fclose(monout);
1257     }