ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/mon/src/mon.cpp
Revision: 1.21
Committed: 2003-09-27T20:30:44Z (20 years, 7 months ago) by cebix
Branch: MAIN
Changes since 1.20: +15 -4 lines
Log Message:
EOF quits cxmon instead of producing a segfault

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.15 * cxmon (C) 1997-2002 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     static char input[INPUT_LENGTH];
70     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     enum Token mon_token; // Last token read
82 gbeauche 1.18 uintptr mon_number; // Contains the number if mon_token==T_NUMBER
83 cebix 1.1 char mon_string[INPUT_LENGTH]; // Contains the string if mon_token==T_STRING
84     char mon_name[INPUT_LENGTH]; // Contains the variable name if mon_token==T_NAME
85    
86    
87     // List of installed commands
88     struct CmdSpec {
89     const char *name; // Name of command
90     void (*func)(void); // Function that executes this command
91     };
92    
93     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    
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     static void init_abort(void);
105     static void exit_abort(void);
106    
107     static void read_line(char *prompt); // Scanner
108     static char get_char(void);
109     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.1 static enum Token get_string(char *str);
114 gbeauche 1.18 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     void mon_add_command(const char *name, void (*func)(void), const char *help_text)
129     {
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     static void init_abort(void)
174     {
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     static void exit_abort(void)
188     {
189     my_sa.sa_handler = SIG_DFL;
190     sigaction(SIGINT, &my_sa, NULL);
191     }
192    
193     bool mon_aborted(void)
194     {
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     if (line_read) {
264     free(line_read);
265     line_read = NULL;
266     }
267    
268     line_read = readline(prompt);
269    
270 cebix 1.21 if (line_read) {
271 cebix 1.1
272 cebix 1.21 if (*line_read)
273     add_history(line_read);
274    
275     strncpy(in_ptr = input, line_read, INPUT_LENGTH);
276     input[INPUT_LENGTH-1] = 0;
277    
278     } else {
279    
280     // EOF, quit cxmon
281     fprintf(monout, "x\n");
282     input[0] = 'x';
283     input[1] = 0;
284     in_ptr = input;
285     }
286 cebix 1.4 #else
287     fprintf(monout, prompt);
288     fflush(monout);
289     fgets(in_ptr = input, INPUT_LENGTH, monin);
290     char *s = strchr(input, '\n');
291     if (s != NULL)
292     *s = 0;
293     #endif
294 cebix 1.1 }
295    
296    
297     /*
298     * Read a character from the input line
299     */
300    
301     static char get_char(void)
302     {
303     return *in_ptr++;
304     }
305    
306    
307     /*
308     * Stuff back a character into the input line
309     */
310    
311     static void put_back(char c)
312     {
313     *(--in_ptr) = c;
314     }
315    
316    
317     /*
318     * Scanner: Get a token from the input line
319     */
320    
321     enum Token mon_get_token(void)
322     {
323     char c;
324    
325     // Skip spaces
326     while ((c = get_char()) == ' ') ;
327    
328     switch (c) {
329     case 0:
330     return mon_token = T_END;
331     case '(':
332     return mon_token = T_LPAREN;
333     case ')':
334     return mon_token = T_RPAREN;
335     case '.':
336     return mon_token = T_DOT;
337     case ':':
338     return mon_token = T_COLON;
339     case ',':
340     return mon_token = T_COMMA;
341     case '+':
342     return mon_token = T_PLUS;
343     case '-':
344     return mon_token = T_MINUS;
345     case '*':
346     return mon_token = T_MUL;
347     case '/':
348     return mon_token = T_DIV;
349     case '%':
350     return mon_token = T_MOD;
351     case '&':
352     return mon_token = T_AND;
353     case '|':
354     return mon_token = T_OR;
355     case '^':
356     return mon_token = T_EOR;
357     case '<':
358     if (get_char() == '<')
359     return mon_token = T_SHIFTL;
360     else {
361     mon_error("Unrecognized token");
362     return mon_token = T_NULL;
363     }
364     case '>':
365     if (get_char() == '>')
366     return mon_token = T_SHIFTR;
367     else {
368     mon_error("Unrecognized token");
369     return mon_token = T_NULL;
370     }
371     case '~':
372     return mon_token = T_NOT;
373     case '=':
374     return mon_token = T_ASSIGN;
375    
376     case '$':
377     if ((mon_token = get_hex_number(mon_number)) == T_NULL)
378     mon_error("'$' must be followed by hexadecimal number");
379     return mon_token;
380     case '_':
381     if ((mon_token = get_dec_number(mon_number)) == T_NULL)
382     mon_error("'_' must be followed by decimal number");
383     return mon_token;
384     case '\'':
385     return mon_token = get_char_number(mon_number);
386     case '"':
387     return mon_token = get_string(mon_string);
388    
389     default:
390     if (isalnum(c)) {
391     put_back(c);
392     return mon_token = get_hex_or_name(mon_number, mon_name);
393     }
394     mon_error("Unrecognized token");
395     return mon_token = T_NULL;
396     }
397     }
398    
399 gbeauche 1.18 static enum Token get_hex_number(uintptr &i)
400 cebix 1.1 {
401     char c = get_char();
402    
403     i = 0;
404     if (!isxdigit(c))
405     return T_NULL;
406    
407     do {
408 cebix 1.16 c = tolower(c);
409 cebix 1.1 if (c < 'a')
410     i = (i << 4) + (c - '0');
411     else
412     i = (i << 4) + (c - 'a' + 10);
413     c = get_char();
414     } while (isxdigit(c));
415    
416     if (isalnum(c))
417     return T_NULL;
418     else {
419     put_back(c);
420     return T_NUMBER;
421     }
422     }
423    
424 gbeauche 1.18 static enum Token get_dec_number(uintptr &i)
425 cebix 1.1 {
426     char c = get_char();
427    
428     i = 0;
429     if (!isdigit(c))
430     return T_NULL;
431    
432     do {
433     i = (i * 10) + (c - '0');
434     c = get_char();
435     } while (isdigit(c));
436    
437     if (isalnum(c))
438     return T_NULL;
439     else {
440     put_back(c);
441     return T_NUMBER;
442     }
443     }
444    
445 gbeauche 1.18 static enum Token get_char_number(uintptr &i)
446 cebix 1.1 {
447     char c;
448    
449     i = 0;
450     while ((c = get_char()) != 0) {
451     if (c == '\'')
452     return T_NUMBER;
453     i = (i << 8) + (uint8)c;
454     }
455    
456     mon_error("Unterminated character constant");
457     return T_NULL;
458     }
459    
460     static enum Token get_string(char *str)
461     {
462     char c;
463    
464     while ((c = get_char()) != 0) {
465     if (c == '"') {
466     *str = 0;
467     return T_STRING;
468     }
469     *str++ = c;
470     }
471    
472     mon_error("Unterminated string");
473     return T_NULL;
474     }
475    
476 gbeauche 1.18 static enum Token get_hex_or_name(uintptr &i, char *name)
477 cebix 1.1 {
478     char *old_in_ptr = in_ptr;
479     char c;
480    
481     // Try hex number first
482     if (get_hex_number(i) == T_NUMBER)
483     return T_NUMBER;
484    
485     // Not a hex number, must be a variable name
486     in_ptr = old_in_ptr;
487     c = get_char();
488     do {
489     *name++ = c;
490     c = get_char();
491     } while (isalnum(c));
492    
493     *name = 0;
494     put_back(c);
495     return T_NAME;
496     }
497    
498    
499     /*
500     * expression = eor_expr {OR eor_expr}
501     * true: OK, false: Error
502     */
503    
504 gbeauche 1.18 bool mon_expression(uintptr *number)
505 cebix 1.1 {
506 gbeauche 1.18 uintptr accu, expr;
507 cebix 1.1
508     if (!eor_expr(&accu))
509     return false;
510    
511     for (;;)
512     switch (mon_token) {
513     case T_OR:
514     mon_get_token();
515     if (!eor_expr(&expr))
516     return false;
517     accu |= expr;
518     break;
519    
520     default:
521     *number = accu;
522     return true;
523     }
524     }
525    
526    
527     /*
528     * eor_expr = and_expr {EOR and_expr}
529     * true: OK, false: Error
530     */
531    
532 gbeauche 1.18 static bool eor_expr(uintptr *number)
533 cebix 1.1 {
534 gbeauche 1.18 uintptr accu, expr;
535 cebix 1.1
536     if (!and_expr(&accu))
537     return false;
538    
539     for (;;)
540     switch (mon_token) {
541     case T_EOR:
542     mon_get_token();
543     if (!and_expr(&expr))
544     return false;
545     accu ^= expr;
546     break;
547    
548     default:
549     *number = accu;
550     return true;
551     }
552     }
553    
554    
555     /*
556     * and_expr = shift_expr {AND shift_expr}
557     * true: OK, false: Error
558     */
559    
560 gbeauche 1.18 static bool and_expr(uintptr *number)
561 cebix 1.1 {
562 gbeauche 1.18 uintptr accu, expr;
563 cebix 1.1
564     if (!shift_expr(&accu))
565     return false;
566    
567     for (;;)
568     switch (mon_token) {
569     case T_AND:
570     mon_get_token();
571     if (!shift_expr(&expr))
572     return false;
573     accu &= expr;
574     break;
575    
576     default:
577     *number = accu;
578     return true;
579     }
580     }
581    
582    
583     /*
584     * shift_expr = add_expr {(SHIFTL | SHIFTR) add_expr}
585     * true: OK, false: Error
586     */
587    
588 gbeauche 1.18 static bool shift_expr(uintptr *number)
589 cebix 1.1 {
590 gbeauche 1.18 uintptr accu, expr;
591 cebix 1.1
592     if (!add_expr(&accu))
593     return false;
594    
595     for (;;)
596     switch (mon_token) {
597     case T_SHIFTL:
598     mon_get_token();
599     if (!add_expr(&expr))
600     return false;
601     accu <<= expr;
602     break;
603    
604     case T_SHIFTR:
605     mon_get_token();
606     if (!add_expr(&expr))
607     return false;
608     accu >>= expr;
609     break;
610    
611     default:
612     *number = accu;
613     return true;
614     }
615     }
616    
617    
618     /*
619     * add_expr = mul_expr {(PLUS | MINUS) mul_expr}
620     * true: OK, false: Error
621     */
622    
623 gbeauche 1.18 static bool add_expr(uintptr *number)
624 cebix 1.1 {
625 gbeauche 1.18 uintptr accu, expr;
626 cebix 1.1
627     if (!mul_expr(&accu))
628     return false;
629    
630     for (;;)
631     switch (mon_token) {
632     case T_PLUS:
633     mon_get_token();
634     if (!mul_expr(&expr))
635     return false;
636     accu += expr;
637     break;
638    
639     case T_MINUS:
640     mon_get_token();
641     if (!mul_expr(&expr))
642     return false;
643     accu -= expr;
644     break;
645    
646     default:
647     *number = accu;
648     return true;
649     }
650     }
651    
652    
653     /*
654     * mul_expr = factor {(MUL | DIV | MOD) factor}
655     * true: OK, false: Error
656     */
657    
658 gbeauche 1.18 static bool mul_expr(uintptr *number)
659 cebix 1.1 {
660 gbeauche 1.18 uintptr accu, fact;
661 cebix 1.1
662     if (!factor(&accu))
663     return false;
664    
665     for (;;)
666     switch (mon_token) {
667     case T_MUL:
668     mon_get_token();
669     if (!factor(&fact))
670     return false;
671     accu *= fact;
672     break;
673    
674     case T_DIV:
675     mon_get_token();
676     if (!factor(&fact))
677     return false;
678     if (fact == 0) {
679     mon_error("Division by 0");
680     return false;
681     }
682     accu /= fact;
683     break;
684    
685     case T_MOD:
686     mon_get_token();
687     if (!factor(&fact))
688     return false;
689     if (fact == 0) {
690     mon_error("Division by 0");
691     return false;
692     }
693     accu %= fact;
694     break;
695    
696     default:
697     *number = accu;
698     return true;
699     }
700     }
701    
702    
703     /*
704     * factor = NUMBER | NAME | DOT | COLON | (PLUS | MINUS | NOT) factor | LPAREN expression RPAREN
705     * true: OK, false: Error
706     */
707    
708 gbeauche 1.18 static bool factor(uintptr *number)
709 cebix 1.1 {
710     switch (mon_token) {
711     case T_NUMBER:
712     *number = mon_number;
713     mon_get_token();
714     return true;
715    
716     case T_NAME:{
717 cebix 1.15 var_map::const_iterator v = vars.find(mon_name);
718     if (v == vars.end())
719     return false;
720     else {
721     *number = v->second;
722 cebix 1.1 mon_get_token();
723     return true;
724 cebix 1.15 }
725 cebix 1.1 }
726    
727     case T_DOT:
728     *number = mon_dot_address;
729     mon_get_token();
730     return true;
731    
732     case T_COLON:
733     *number = colon_value;
734     mon_get_token();
735     return true;
736    
737     case T_PLUS:
738     mon_get_token();
739     return factor(number);
740    
741     case T_MINUS:
742     mon_get_token();
743     if (factor(number)) {
744     *number = -*number;
745     return true;
746     } else
747     return false;
748    
749     case T_NOT:
750     mon_get_token();
751     if (factor(number)) {
752     *number = ~*number;
753     return true;
754     } else
755     return false;
756    
757     case T_LPAREN:
758     mon_get_token();
759     if (mon_expression(number))
760     if (mon_token == T_RPAREN) {
761     mon_get_token();
762     return true;
763     } else {
764     mon_error("Missing ')'");
765     return false;
766     }
767     else {
768     mon_error("Error in expression");
769     return false;
770     }
771    
772     case T_END:
773     mon_error("Required argument missing");
774     return false;
775    
776     default:
777     mon_error("'(' or number expected");
778     return false;
779     }
780     }
781    
782    
783     /*
784     * Set/clear/show variables
785     * set [var[=value]]
786     */
787    
788     static void set_var(void)
789     {
790     if (mon_token == T_END) {
791    
792     // Show all variables
793 cebix 1.15 if (vars.empty())
794 cebix 1.1 fprintf(monout, "No variables defined\n");
795 cebix 1.15 else {
796     var_map::const_iterator v = vars.begin(), end = vars.end();
797     for (v=vars.begin(); v!=end; ++v)
798     fprintf(monout, "%s = %08x\n", v->first.c_str(), v->second);
799     }
800 cebix 1.1
801     } else if (mon_token == T_NAME) {
802 gbeauche 1.17 std::string var_name = mon_name;
803 cebix 1.1 mon_get_token();
804     if (mon_token == T_ASSIGN) {
805    
806     // Set variable
807 gbeauche 1.18 uintptr value;
808 cebix 1.1 mon_get_token();
809     if (!mon_expression(&value))
810     return;
811     if (mon_token != T_END) {
812     mon_error("Too many arguments");
813     return;
814     }
815 cebix 1.15 vars[var_name] = value;
816 cebix 1.1
817     } else if (mon_token == T_END) {
818    
819     // Clear variable
820 cebix 1.15 vars.erase(var_name);
821 cebix 1.1
822     } else
823     mon_error("'=' expected");
824     } else
825     mon_error("Variable name expected");
826     }
827    
828    
829     /*
830     * Clear all variables
831     * cv
832     */
833    
834     static void clear_vars(void)
835     {
836 cebix 1.15 vars.clear();
837 cebix 1.1 }
838    
839    
840     /*
841     * Display help
842     * h
843     */
844    
845     static void help_or_hunt(void)
846     {
847     if (mon_token != T_END) {
848     hunt();
849     return;
850     }
851     fprintf(monout, "x Quit mon\n"
852     "h This help text\n");
853     fprintf(monout, cmd_help);
854     }
855    
856    
857     /*
858     * Display command list
859     * ??
860     */
861    
862     static void mon_cmd_list(void)
863     {
864     for (int i=0; i<num_cmds; i++)
865     fprintf(monout, "%s ", cmds[i].name);
866     fprintf(monout, "\n");
867     }
868    
869    
870     /*
871     * Reallocate buffer
872     * @ [size]
873     */
874    
875     static void reallocate(void)
876     {
877 gbeauche 1.18 uintptr size;
878 cebix 1.1
879     if (mon_use_real_mem) {
880     fprintf(monerr, "Cannot reallocate buffer in real mode\n");
881     return;
882     }
883    
884     if (mon_token == T_END) {
885 cebix 1.3 fprintf(monerr, "Buffer size: %08x bytes\n", mon_mem_size);
886 cebix 1.1 return;
887     }
888    
889     if (!mon_expression(&size))
890     return;
891     if (mon_token != T_END) {
892     mon_error("Too many arguments");
893     return;
894     }
895    
896     if ((mem = (uint8 *)realloc(mem, size)) != NULL)
897 cebix 1.3 fprintf(monerr, "Buffer size: %08x bytes\n", mon_mem_size = size);
898 cebix 1.1 else
899     fprintf(monerr, "Unable to reallocate buffer\n");
900     }
901    
902    
903     /*
904     * Apply expression to memory
905     * y[b|h|w] start end expression
906     */
907    
908     static void apply(int size)
909     {
910 gbeauche 1.18 uintptr adr, end_adr, value;
911 cebix 1.1 char c;
912    
913     if (!mon_expression(&adr))
914     return;
915     if (!mon_expression(&end_adr))
916     return;
917     if (!mon_expression(&value))
918     return;
919     if (mon_token != T_END) {
920     mon_error("Too many arguments");
921     return;
922     }
923    
924 gbeauche 1.18 uint32 (*read_func)(uintptr adr);
925     void (*write_func)(uintptr adr, uint32 val);
926 cebix 1.1 switch (size) {
927     case 1:
928     read_func = mon_read_byte;
929     write_func = mon_write_byte;
930     break;
931     case 2:
932     read_func = mon_read_half;
933     write_func = mon_write_half;
934     break;
935     case 4:
936     read_func = mon_read_word;
937     write_func = mon_write_word;
938     break;
939 cebix 1.3 default:
940     abort();
941     break;
942 cebix 1.1 }
943    
944     while (adr<=end_adr) {
945     colon_value = read_func(adr);
946     mon_dot_address = adr;
947    
948     in_ptr = input;
949     while ((c = get_char()) == ' ') ;
950     while ((c = get_char()) != ' ') ;
951     while ((c = get_char()) == ' ') ;
952     put_back(c);
953     mon_get_token();
954     mon_expression(&value); // Skip start address
955     mon_expression(&value); // Skip end address
956     mon_expression(&value);
957    
958     write_func(adr, value);
959     adr += size;
960     }
961    
962     mon_dot_address = adr;
963     }
964    
965     static void apply_byte(void)
966     {
967     apply(1);
968     }
969    
970     static void apply_half(void)
971     {
972     apply(2);
973     }
974    
975     static void apply_word(void)
976     {
977     apply(4);
978     }
979    
980    
981     /*
982     * Execute command via system() (for ls, rm, etc.)
983     */
984    
985     static void mon_exec(void)
986     {
987     system(input);
988     }
989    
990    
991     /*
992     * Change current directory
993     */
994    
995     static void mon_change_dir(void)
996     {
997     char c;
998     in_ptr = input;
999     while ((c = get_char()) == ' ') ;
1000     while ((c = get_char()) != ' ') ;
1001     while ((c = get_char()) == ' ') ;
1002     put_back(c);
1003     if (chdir(in_ptr) != 0)
1004     mon_error("Cannot change directory");
1005     }
1006    
1007    
1008     /*
1009     * Initialize mon
1010     */
1011    
1012     void mon_init(void)
1013     {
1014     cmds = NULL;
1015     num_cmds = 0;
1016     cmd_help = NULL;
1017    
1018 cebix 1.12 mon_add_command("??", mon_cmd_list, "?? Show list of commands\n");
1019     mon_add_command("ver", version, "ver Show version\n");
1020     mon_add_command("?", print_expr, "? expression Calculate expression\n");
1021     mon_add_command("@", reallocate, "@ [size] Reallocate buffer\n");
1022     mon_add_command("i", ascii_dump, "i [start [end]] ASCII memory dump\n");
1023     mon_add_command("m", memory_dump, "m [start [end]] Hex/ASCII memory dump\n");
1024     mon_add_command("b", binary_dump, "b [start [end]] Binary memory dump\n");
1025     mon_add_command("d", disassemble_ppc, "d [start [end]] Disassemble PowerPC code\n");
1026     mon_add_command("d65", disassemble_6502, "d65 [start [end]] Disassemble 6502 code\n");
1027     mon_add_command("d68", disassemble_680x0, "d68 [start [end]] Disassemble 680x0 code\n");
1028 cebix 1.14 mon_add_command("d80", disassemble_z80, "d80 [start [end]] Disassemble Z80 code\n");
1029 cebix 1.12 mon_add_command("d86", disassemble_80x86_32, "d86 [start [end]] Disassemble 80x86 (32-bit) code\n");
1030 cebix 1.13 mon_add_command("d8086", disassemble_80x86_16, "d8086 [start [end]] Disassemble 80x86 (16-bit) code\n");
1031 gbeauche 1.20 mon_add_command("d8664", disassemble_x86_64, "d8664 [start [end]] Disassemble x86-64 code\n");
1032 cebix 1.12 mon_add_command(":", modify, ": start string Modify memory\n");
1033     mon_add_command("f", fill, "f start end string Fill memory\n");
1034     mon_add_command("y", apply_byte, "y[b|h|w] start end expr Apply expression to memory\n");
1035 cebix 1.1 mon_add_command("yb", apply_byte, NULL);
1036     mon_add_command("yh", apply_half, NULL);
1037     mon_add_command("yw", apply_word, NULL);
1038 cebix 1.12 mon_add_command("t", transfer, "t start end dest Transfer memory\n");
1039     mon_add_command("c", compare, "c start end dest Compare memory\n");
1040     mon_add_command("h", help_or_hunt, "h start end string Search for byte string\n");
1041     mon_add_command("\\", shell_command, "\\ \"command\" Execute shell command\n");
1042     mon_add_command("ls", mon_exec, "ls [args] List directory contents\n");
1043     mon_add_command("rm", mon_exec, "rm [args] Remove file(s)\n");
1044     mon_add_command("cp", mon_exec, "cp [args] Copy file(s)\n");
1045     mon_add_command("mv", mon_exec, "mv [args] Move file(s)\n");
1046     mon_add_command("cd", mon_change_dir, "cd directory Change current directory\n");
1047     mon_add_command("o", redir_output, "o [\"file\"] Redirect output\n");
1048     mon_add_command("[", load_data, "[ start \"file\" Load data from file\n");
1049     mon_add_command("]", save_data, "] start size \"file\" Save data to file\n");
1050     mon_add_command("set", set_var, "set [var[=value]] Set/clear/show variables\n");
1051     mon_add_command("cv", clear_vars, "cv Clear all variables\n");
1052 cebix 1.5
1053     mon_read_byte = NULL;
1054     mon_write_byte = NULL;
1055 cebix 1.1 }
1056    
1057    
1058     /*
1059     * Deinitialize mon
1060     */
1061    
1062     void mon_exit(void)
1063     {
1064     free(cmds);
1065     cmds = NULL;
1066     num_cmds = 0;
1067     cmd_help = NULL;
1068     }
1069    
1070    
1071     /*
1072     * Main function, read-execute loop
1073     */
1074    
1075     void mon(int argc, char **argv)
1076     {
1077     bool done = false, interactive = true;
1078     char c, cmd[INPUT_LENGTH];
1079    
1080     // Setup input/output streams
1081     monin = stdin;
1082     monout = stdout;
1083     monerr = stdout;
1084    
1085 cebix 1.11 // Make argc/argv point to the actual arguments
1086 cebix 1.15 const char *prg_name = argv[0];
1087 cebix 1.11 if (argc)
1088     argc--; argv++;
1089    
1090     // Parse arguments
1091     mon_macos_mode = false;
1092     mon_use_real_mem = false;
1093     while (argc > 0) {
1094 cebix 1.15 if (strcmp(argv[0], "-h") == 0 || strcmp(argv[0], "--help") == 0) {
1095     printf("Usage: %s [-m] [-r] [command...]\n", prg_name);
1096     exit(0);
1097     } else if (strcmp(argv[0], "-m") == 0)
1098 cebix 1.11 mon_macos_mode = true;
1099     else if (strcmp(argv[0], "-r") == 0)
1100 cebix 1.1 mon_use_real_mem = true;
1101 cebix 1.11 else
1102     break;
1103     argc--; argv++;
1104 cebix 1.1 }
1105 cebix 1.11 interactive = (argc == 0);
1106 cebix 1.1
1107 cebix 1.5 // Set up memory access functions if not supplied by the user
1108     if (mon_read_byte == NULL) {
1109     if (mon_use_real_mem)
1110     mon_read_byte = mon_read_byte_real;
1111     else
1112     mon_read_byte = mon_read_byte_buffer;
1113     }
1114     if (mon_write_byte == NULL) {
1115     if (mon_use_real_mem)
1116     mon_write_byte = mon_write_byte_real;
1117     else
1118     mon_write_byte = mon_write_byte_buffer;
1119     }
1120    
1121 cebix 1.1 // Allocate buffer
1122     if (!mon_use_real_mem) {
1123     mon_mem_size = 0x100000;
1124     mem = (uint8 *)malloc(mon_mem_size);
1125    
1126     // Print banner
1127     if (interactive)
1128 cebix 1.14 fprintf(monerr, "\n *** cxmon V" VERSION " by Christian Bauer and Marc Hellwig ***\n"
1129     " *** Press 'h' for help ***\n\n");
1130 cebix 1.15 }
1131    
1132     // Clear variables
1133     vars.clear();
1134    
1135     // In MacOS mode, pull in the lowmem globals as variables
1136     if (mon_macos_mode) {
1137     const lowmem_info *l = lowmem;
1138     while (l->name) {
1139     vars[l->name] = l->addr;
1140     l++;
1141     }
1142 cebix 1.1 }
1143    
1144     init_abort();
1145    
1146     // Read and parse command line
1147     while (!done) {
1148     if (interactive) {
1149     char prompt[16];
1150 gbeauche 1.18 sprintf(prompt, "[%0*lx]-> ", 2 * sizeof(mon_dot_address), mon_dot_address);
1151 cebix 1.1 read_line(prompt);
1152     } else {
1153     if (argc == 0) {
1154     done = true;
1155     break;
1156     } else {
1157     strncpy(in_ptr = input, argv[0], INPUT_LENGTH);
1158     argc--;
1159     argv++;
1160     }
1161     }
1162    
1163     // Skip leading spaces
1164     while ((c = get_char()) == ' ') ;
1165    
1166     // Read command word
1167     char *p = cmd;
1168     do {
1169     *p++ = c;
1170     c = get_char();
1171     } while (isgraph(c));
1172     *p = 0;
1173     put_back(c);
1174    
1175     // Execute command
1176     if (cmd[0] == 0) // Blank line
1177     continue;
1178     if (strcmp(cmd, "x") == 0) { // Exit
1179     done = true;
1180     continue;
1181     }
1182     for (int i=0; i<num_cmds; i++) {
1183     if (strcmp(cmd, cmds[i].name) == 0) {
1184     mon_get_token();
1185     cmds[i].func();
1186     goto cmd_done;
1187     }
1188     }
1189     mon_error("Unknown command");
1190     cmd_done: ;
1191     }
1192    
1193     exit_abort();
1194    
1195     // Free buffer
1196     if (!mon_use_real_mem)
1197     free(mem);
1198    
1199     // Close output file if redirected
1200     if (monout != monerr)
1201     fclose(monout);
1202     }