ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/mon/src/mon.cpp
Revision: 1.20
Committed: 2002-09-07T12:48:15Z (21 years, 8 months ago) by gbeauche
Branch: MAIN
Changes since 1.19: +1 -0 lines
Log Message:
Add support for x86-64 disassembly
- mon.cpp (mon_init): new command is "d8664"
- mon_cmd.cpp (disassemble): handle CPU_x86_64, and make it 64-bit aware in
  address dumps
- mon_disass.cpp (disass_x86): s/bool i8086/uint32 bits/ defining the x86
  architecture "size", aka 16 => 8086, 32 => 80x86, 64 => x86-64
- Merge with GNU x86 disassembler as part of binutils 2.12.90.0.15

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