ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/mon/src/mon.cpp
Revision: 1.27
Committed: 2007-06-07T09:51:56Z (17 years, 5 months ago) by gbeauche
Branch: MAIN
Changes since 1.26: +2 -0 lines
Log Message:
Add MIPS disassembler invoked as "dm" and "dmel" (little-endian) for now.

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.25 * cxmon (C) 1997-2004 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.23 if (input)
262     free(input);
263     input = readline(prompt);
264    
265     if (input) {
266     if (*input)
267     add_history(input);
268 cebix 1.21 } else {
269     // EOF, quit cxmon
270 cebix 1.23 input = (char *)malloc(2);
271 cebix 1.21 input[0] = 'x';
272     input[1] = 0;
273 cebix 1.23 fprintf(monout, "x\n");
274 cebix 1.21 }
275 cebix 1.23
276     in_ptr = input;
277 cebix 1.4 #else
278 cebix 1.24 static const unsigned INPUT_LENGTH = 256;
279 cebix 1.23 if (!input)
280     input = (char *)malloc(INPUT_LENGTH);
281 cebix 1.4 fprintf(monout, prompt);
282     fflush(monout);
283     fgets(in_ptr = input, INPUT_LENGTH, monin);
284     char *s = strchr(input, '\n');
285     if (s != NULL)
286     *s = 0;
287     #endif
288 cebix 1.1 }
289    
290    
291     /*
292     * Read a character from the input line
293     */
294    
295 cebix 1.23 static char get_char()
296 cebix 1.1 {
297     return *in_ptr++;
298     }
299    
300    
301     /*
302     * Stuff back a character into the input line
303     */
304    
305     static void put_back(char c)
306     {
307     *(--in_ptr) = c;
308     }
309    
310    
311     /*
312     * Scanner: Get a token from the input line
313     */
314    
315 cebix 1.23 enum Token mon_get_token()
316 cebix 1.1 {
317 cebix 1.23 char c = get_char();
318 cebix 1.1
319     // Skip spaces
320 cebix 1.23 while (isspace(c))
321     c = get_char();
322 cebix 1.1
323     switch (c) {
324     case 0:
325     return mon_token = T_END;
326     case '(':
327     return mon_token = T_LPAREN;
328     case ')':
329     return mon_token = T_RPAREN;
330     case '.':
331     return mon_token = T_DOT;
332     case ':':
333     return mon_token = T_COLON;
334     case ',':
335     return mon_token = T_COMMA;
336     case '+':
337     return mon_token = T_PLUS;
338     case '-':
339     return mon_token = T_MINUS;
340     case '*':
341     return mon_token = T_MUL;
342     case '/':
343     return mon_token = T_DIV;
344     case '%':
345     return mon_token = T_MOD;
346     case '&':
347     return mon_token = T_AND;
348     case '|':
349     return mon_token = T_OR;
350     case '^':
351     return mon_token = T_EOR;
352     case '<':
353     if (get_char() == '<')
354     return mon_token = T_SHIFTL;
355     else {
356     mon_error("Unrecognized token");
357     return mon_token = T_NULL;
358     }
359     case '>':
360     if (get_char() == '>')
361     return mon_token = T_SHIFTR;
362     else {
363     mon_error("Unrecognized token");
364     return mon_token = T_NULL;
365     }
366     case '~':
367     return mon_token = T_NOT;
368     case '=':
369     return mon_token = T_ASSIGN;
370    
371     case '$':
372     if ((mon_token = get_hex_number(mon_number)) == T_NULL)
373     mon_error("'$' must be followed by hexadecimal number");
374     return mon_token;
375     case '_':
376     if ((mon_token = get_dec_number(mon_number)) == T_NULL)
377     mon_error("'_' must be followed by decimal number");
378     return mon_token;
379     case '\'':
380     return mon_token = get_char_number(mon_number);
381     case '"':
382     return mon_token = get_string(mon_string);
383    
384     default:
385     if (isalnum(c)) {
386     put_back(c);
387     return mon_token = get_hex_or_name(mon_number, mon_name);
388     }
389     mon_error("Unrecognized token");
390     return mon_token = T_NULL;
391     }
392     }
393    
394 gbeauche 1.18 static enum Token get_hex_number(uintptr &i)
395 cebix 1.1 {
396     char c = get_char();
397    
398     i = 0;
399     if (!isxdigit(c))
400     return T_NULL;
401    
402     do {
403 cebix 1.16 c = tolower(c);
404 cebix 1.1 if (c < 'a')
405     i = (i << 4) + (c - '0');
406     else
407     i = (i << 4) + (c - 'a' + 10);
408     c = get_char();
409     } while (isxdigit(c));
410    
411     if (isalnum(c))
412     return T_NULL;
413     else {
414     put_back(c);
415     return T_NUMBER;
416     }
417     }
418    
419 gbeauche 1.18 static enum Token get_dec_number(uintptr &i)
420 cebix 1.1 {
421     char c = get_char();
422    
423     i = 0;
424     if (!isdigit(c))
425     return T_NULL;
426    
427     do {
428     i = (i * 10) + (c - '0');
429     c = get_char();
430     } while (isdigit(c));
431    
432     if (isalnum(c))
433     return T_NULL;
434     else {
435     put_back(c);
436     return T_NUMBER;
437     }
438     }
439    
440 gbeauche 1.18 static enum Token get_char_number(uintptr &i)
441 cebix 1.1 {
442     char c;
443    
444     i = 0;
445     while ((c = get_char()) != 0) {
446     if (c == '\'')
447     return T_NUMBER;
448     i = (i << 8) + (uint8)c;
449     }
450    
451     mon_error("Unterminated character constant");
452     return T_NULL;
453     }
454    
455 cebix 1.23 static enum Token get_string(char *&str)
456 cebix 1.1 {
457 cebix 1.23 // Remember start of string
458     char *old_in_ptr = in_ptr;
459    
460     // Determine string length
461 cebix 1.1 char c;
462 cebix 1.23 unsigned n = 0;
463 cebix 1.1 while ((c = get_char()) != 0) {
464 cebix 1.23 n++;
465     if (c == '"')
466     break;
467     }
468     if (c == 0) {
469     mon_error("Unterminated string");
470     return T_NULL;
471 cebix 1.1 }
472    
473 cebix 1.23 // Allocate new buffer (n: size needed including terminating 0)
474     str = (char *)realloc(str, n);
475    
476     // Copy string to buffer
477     char *p = str;
478     in_ptr = old_in_ptr;
479     while (--n)
480     *p++ = get_char();
481     *p++ = 0;
482     get_char(); // skip closing '"'
483     return T_STRING;
484 cebix 1.1 }
485    
486 cebix 1.23 static enum Token get_hex_or_name(uintptr &i, char *&name)
487 cebix 1.1 {
488 cebix 1.23 // Remember start of token
489 cebix 1.1 char *old_in_ptr = in_ptr;
490    
491     // Try hex number first
492     if (get_hex_number(i) == T_NUMBER)
493     return T_NUMBER;
494    
495 cebix 1.23 // Not a hex number, must be a variable name; determine its length
496 cebix 1.1 in_ptr = old_in_ptr;
497 cebix 1.23 char c = get_char();
498     unsigned n = 1;
499 cebix 1.1 do {
500 cebix 1.23 n++;
501 cebix 1.1 c = get_char();
502     } while (isalnum(c));
503    
504 cebix 1.23 // Allocate new buffer (n: size needed including terminating 0)
505     name = (char *)realloc(name, n);
506    
507     // Copy name to buffer
508     in_ptr = old_in_ptr;
509     char *p = name;
510     while (--n)
511     *p++ = get_char();
512     *p = 0;
513 cebix 1.1 return T_NAME;
514     }
515    
516    
517     /*
518     * expression = eor_expr {OR eor_expr}
519     * true: OK, false: Error
520     */
521    
522 gbeauche 1.18 bool mon_expression(uintptr *number)
523 cebix 1.1 {
524 gbeauche 1.18 uintptr accu, expr;
525 cebix 1.1
526     if (!eor_expr(&accu))
527     return false;
528    
529     for (;;)
530     switch (mon_token) {
531     case T_OR:
532     mon_get_token();
533     if (!eor_expr(&expr))
534     return false;
535     accu |= expr;
536     break;
537    
538     default:
539     *number = accu;
540     return true;
541     }
542     }
543    
544    
545     /*
546     * eor_expr = and_expr {EOR and_expr}
547     * true: OK, false: Error
548     */
549    
550 gbeauche 1.18 static bool eor_expr(uintptr *number)
551 cebix 1.1 {
552 gbeauche 1.18 uintptr accu, expr;
553 cebix 1.1
554     if (!and_expr(&accu))
555     return false;
556    
557     for (;;)
558     switch (mon_token) {
559     case T_EOR:
560     mon_get_token();
561     if (!and_expr(&expr))
562     return false;
563     accu ^= expr;
564     break;
565    
566     default:
567     *number = accu;
568     return true;
569     }
570     }
571    
572    
573     /*
574     * and_expr = shift_expr {AND shift_expr}
575     * true: OK, false: Error
576     */
577    
578 gbeauche 1.18 static bool and_expr(uintptr *number)
579 cebix 1.1 {
580 gbeauche 1.18 uintptr accu, expr;
581 cebix 1.1
582     if (!shift_expr(&accu))
583     return false;
584    
585     for (;;)
586     switch (mon_token) {
587     case T_AND:
588     mon_get_token();
589     if (!shift_expr(&expr))
590     return false;
591     accu &= expr;
592     break;
593    
594     default:
595     *number = accu;
596     return true;
597     }
598     }
599    
600    
601     /*
602     * shift_expr = add_expr {(SHIFTL | SHIFTR) add_expr}
603     * true: OK, false: Error
604     */
605    
606 gbeauche 1.18 static bool shift_expr(uintptr *number)
607 cebix 1.1 {
608 gbeauche 1.18 uintptr accu, expr;
609 cebix 1.1
610     if (!add_expr(&accu))
611     return false;
612    
613     for (;;)
614     switch (mon_token) {
615     case T_SHIFTL:
616     mon_get_token();
617     if (!add_expr(&expr))
618     return false;
619     accu <<= expr;
620     break;
621    
622     case T_SHIFTR:
623     mon_get_token();
624     if (!add_expr(&expr))
625     return false;
626     accu >>= expr;
627     break;
628    
629     default:
630     *number = accu;
631     return true;
632     }
633     }
634    
635    
636     /*
637     * add_expr = mul_expr {(PLUS | MINUS) mul_expr}
638     * true: OK, false: Error
639     */
640    
641 gbeauche 1.18 static bool add_expr(uintptr *number)
642 cebix 1.1 {
643 gbeauche 1.18 uintptr accu, expr;
644 cebix 1.1
645     if (!mul_expr(&accu))
646     return false;
647    
648     for (;;)
649     switch (mon_token) {
650     case T_PLUS:
651     mon_get_token();
652     if (!mul_expr(&expr))
653     return false;
654     accu += expr;
655     break;
656    
657     case T_MINUS:
658     mon_get_token();
659     if (!mul_expr(&expr))
660     return false;
661     accu -= expr;
662     break;
663    
664     default:
665     *number = accu;
666     return true;
667     }
668     }
669    
670    
671     /*
672     * mul_expr = factor {(MUL | DIV | MOD) factor}
673     * true: OK, false: Error
674     */
675    
676 gbeauche 1.18 static bool mul_expr(uintptr *number)
677 cebix 1.1 {
678 gbeauche 1.18 uintptr accu, fact;
679 cebix 1.1
680     if (!factor(&accu))
681     return false;
682    
683     for (;;)
684     switch (mon_token) {
685     case T_MUL:
686     mon_get_token();
687     if (!factor(&fact))
688     return false;
689     accu *= fact;
690     break;
691    
692     case T_DIV:
693     mon_get_token();
694     if (!factor(&fact))
695     return false;
696     if (fact == 0) {
697     mon_error("Division by 0");
698     return false;
699     }
700     accu /= fact;
701     break;
702    
703     case T_MOD:
704     mon_get_token();
705     if (!factor(&fact))
706     return false;
707     if (fact == 0) {
708     mon_error("Division by 0");
709     return false;
710     }
711     accu %= fact;
712     break;
713    
714     default:
715     *number = accu;
716     return true;
717     }
718     }
719    
720    
721     /*
722     * factor = NUMBER | NAME | DOT | COLON | (PLUS | MINUS | NOT) factor | LPAREN expression RPAREN
723     * true: OK, false: Error
724     */
725    
726 gbeauche 1.18 static bool factor(uintptr *number)
727 cebix 1.1 {
728     switch (mon_token) {
729     case T_NUMBER:
730     *number = mon_number;
731     mon_get_token();
732     return true;
733    
734     case T_NAME:{
735 cebix 1.15 var_map::const_iterator v = vars.find(mon_name);
736     if (v == vars.end())
737     return false;
738     else {
739     *number = v->second;
740 cebix 1.1 mon_get_token();
741     return true;
742 cebix 1.15 }
743 cebix 1.1 }
744    
745     case T_DOT:
746     *number = mon_dot_address;
747     mon_get_token();
748     return true;
749    
750     case T_COLON:
751     *number = colon_value;
752     mon_get_token();
753     return true;
754    
755     case T_PLUS:
756     mon_get_token();
757     return factor(number);
758    
759     case T_MINUS:
760     mon_get_token();
761     if (factor(number)) {
762     *number = -*number;
763     return true;
764     } else
765     return false;
766    
767     case T_NOT:
768     mon_get_token();
769     if (factor(number)) {
770     *number = ~*number;
771     return true;
772     } else
773     return false;
774    
775     case T_LPAREN:
776     mon_get_token();
777     if (mon_expression(number))
778     if (mon_token == T_RPAREN) {
779     mon_get_token();
780     return true;
781     } else {
782     mon_error("Missing ')'");
783     return false;
784     }
785     else {
786     mon_error("Error in expression");
787     return false;
788     }
789    
790     case T_END:
791     mon_error("Required argument missing");
792     return false;
793    
794     default:
795     mon_error("'(' or number expected");
796     return false;
797     }
798     }
799    
800    
801     /*
802     * Set/clear/show variables
803     * set [var[=value]]
804     */
805    
806 cebix 1.23 static void set_var()
807 cebix 1.1 {
808     if (mon_token == T_END) {
809    
810     // Show all variables
811 cebix 1.15 if (vars.empty())
812 cebix 1.1 fprintf(monout, "No variables defined\n");
813 cebix 1.15 else {
814     var_map::const_iterator v = vars.begin(), end = vars.end();
815     for (v=vars.begin(); v!=end; ++v)
816 cebix 1.26 fprintf(monout, "%s = %08lx\n", v->first.c_str(), v->second);
817 cebix 1.15 }
818 cebix 1.1
819     } else if (mon_token == T_NAME) {
820 gbeauche 1.17 std::string var_name = mon_name;
821 cebix 1.1 mon_get_token();
822     if (mon_token == T_ASSIGN) {
823    
824     // Set variable
825 gbeauche 1.18 uintptr value;
826 cebix 1.1 mon_get_token();
827     if (!mon_expression(&value))
828     return;
829     if (mon_token != T_END) {
830     mon_error("Too many arguments");
831     return;
832     }
833 cebix 1.15 vars[var_name] = value;
834 cebix 1.1
835     } else if (mon_token == T_END) {
836    
837     // Clear variable
838 cebix 1.15 vars.erase(var_name);
839 cebix 1.1
840     } else
841     mon_error("'=' expected");
842     } else
843     mon_error("Variable name expected");
844     }
845    
846    
847     /*
848     * Clear all variables
849     * cv
850     */
851    
852 cebix 1.23 static void clear_vars()
853 cebix 1.1 {
854 cebix 1.15 vars.clear();
855 cebix 1.1 }
856    
857    
858     /*
859     * Display help
860     * h
861     */
862    
863 cebix 1.23 static void help_or_hunt()
864 cebix 1.1 {
865     if (mon_token != T_END) {
866     hunt();
867     return;
868     }
869     fprintf(monout, "x Quit mon\n"
870     "h This help text\n");
871     fprintf(monout, cmd_help);
872     }
873    
874    
875     /*
876     * Display command list
877     * ??
878     */
879    
880 cebix 1.23 static void mon_cmd_list()
881 cebix 1.1 {
882     for (int i=0; i<num_cmds; i++)
883     fprintf(monout, "%s ", cmds[i].name);
884     fprintf(monout, "\n");
885     }
886    
887    
888     /*
889     * Reallocate buffer
890     * @ [size]
891     */
892    
893 cebix 1.23 static void reallocate()
894 cebix 1.1 {
895 gbeauche 1.18 uintptr size;
896 cebix 1.1
897     if (mon_use_real_mem) {
898     fprintf(monerr, "Cannot reallocate buffer in real mode\n");
899     return;
900     }
901    
902     if (mon_token == T_END) {
903 cebix 1.3 fprintf(monerr, "Buffer size: %08x bytes\n", mon_mem_size);
904 cebix 1.1 return;
905     }
906    
907     if (!mon_expression(&size))
908     return;
909     if (mon_token != T_END) {
910     mon_error("Too many arguments");
911     return;
912     }
913    
914     if ((mem = (uint8 *)realloc(mem, size)) != NULL)
915 cebix 1.3 fprintf(monerr, "Buffer size: %08x bytes\n", mon_mem_size = size);
916 cebix 1.1 else
917     fprintf(monerr, "Unable to reallocate buffer\n");
918     }
919    
920    
921     /*
922     * Apply expression to memory
923     * y[b|h|w] start end expression
924     */
925    
926     static void apply(int size)
927     {
928 gbeauche 1.18 uintptr adr, end_adr, value;
929 cebix 1.1 char c;
930    
931     if (!mon_expression(&adr))
932     return;
933     if (!mon_expression(&end_adr))
934     return;
935     if (!mon_expression(&value))
936     return;
937     if (mon_token != T_END) {
938     mon_error("Too many arguments");
939     return;
940     }
941    
942 gbeauche 1.18 uint32 (*read_func)(uintptr adr);
943     void (*write_func)(uintptr adr, uint32 val);
944 cebix 1.1 switch (size) {
945     case 1:
946     read_func = mon_read_byte;
947     write_func = mon_write_byte;
948     break;
949     case 2:
950     read_func = mon_read_half;
951     write_func = mon_write_half;
952     break;
953     case 4:
954     read_func = mon_read_word;
955     write_func = mon_write_word;
956     break;
957 cebix 1.3 default:
958     abort();
959     break;
960 cebix 1.1 }
961    
962     while (adr<=end_adr) {
963     colon_value = read_func(adr);
964     mon_dot_address = adr;
965    
966     in_ptr = input;
967     while ((c = get_char()) == ' ') ;
968     while ((c = get_char()) != ' ') ;
969     while ((c = get_char()) == ' ') ;
970     put_back(c);
971     mon_get_token();
972     mon_expression(&value); // Skip start address
973     mon_expression(&value); // Skip end address
974     mon_expression(&value);
975    
976     write_func(adr, value);
977     adr += size;
978     }
979    
980     mon_dot_address = adr;
981     }
982    
983 cebix 1.23 static void apply_byte()
984 cebix 1.1 {
985     apply(1);
986     }
987    
988 cebix 1.23 static void apply_half()
989 cebix 1.1 {
990     apply(2);
991     }
992    
993 cebix 1.23 static void apply_word()
994 cebix 1.1 {
995     apply(4);
996     }
997    
998    
999     /*
1000     * Execute command via system() (for ls, rm, etc.)
1001     */
1002    
1003 cebix 1.23 static void mon_exec()
1004 cebix 1.1 {
1005     system(input);
1006     }
1007    
1008    
1009     /*
1010     * Change current directory
1011     */
1012    
1013 cebix 1.23 void mon_change_dir()
1014 cebix 1.1 {
1015     in_ptr = input;
1016 cebix 1.23 char c = get_char();
1017     while (isspace(c))
1018     c = get_char();
1019     while (isgraph(c))
1020     c = get_char();
1021     while (isspace(c))
1022     c = get_char();
1023 cebix 1.1 put_back(c);
1024     if (chdir(in_ptr) != 0)
1025     mon_error("Cannot change directory");
1026     }
1027    
1028    
1029     /*
1030     * Initialize mon
1031     */
1032    
1033 cebix 1.23 void mon_init()
1034 cebix 1.1 {
1035     cmds = NULL;
1036     num_cmds = 0;
1037     cmd_help = NULL;
1038    
1039 cebix 1.12 mon_add_command("??", mon_cmd_list, "?? Show list of commands\n");
1040     mon_add_command("ver", version, "ver Show version\n");
1041     mon_add_command("?", print_expr, "? expression Calculate expression\n");
1042     mon_add_command("@", reallocate, "@ [size] Reallocate buffer\n");
1043     mon_add_command("i", ascii_dump, "i [start [end]] ASCII memory dump\n");
1044     mon_add_command("m", memory_dump, "m [start [end]] Hex/ASCII memory dump\n");
1045     mon_add_command("b", binary_dump, "b [start [end]] Binary memory dump\n");
1046     mon_add_command("d", disassemble_ppc, "d [start [end]] Disassemble PowerPC code\n");
1047     mon_add_command("d65", disassemble_6502, "d65 [start [end]] Disassemble 6502 code\n");
1048     mon_add_command("d68", disassemble_680x0, "d68 [start [end]] Disassemble 680x0 code\n");
1049 cebix 1.14 mon_add_command("d80", disassemble_z80, "d80 [start [end]] Disassemble Z80 code\n");
1050 cebix 1.12 mon_add_command("d86", disassemble_80x86_32, "d86 [start [end]] Disassemble 80x86 (32-bit) code\n");
1051 cebix 1.13 mon_add_command("d8086", disassemble_80x86_16, "d8086 [start [end]] Disassemble 80x86 (16-bit) code\n");
1052 gbeauche 1.20 mon_add_command("d8664", disassemble_x86_64, "d8664 [start [end]] Disassemble x86-64 code\n");
1053 gbeauche 1.27 mon_add_command("dm", disassemble_mips, "dm [start [end]] Disassemble MIPS code\n");
1054     mon_add_command("dmel", disassemble_mipsel, "dmel [start [end]] Disassemble MIPS (little-endian) 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 cebix 1.26 sprintf(prompt, "[%0*lx]-> ", int(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     }