/* * mon_cmd.cpp - cxmon standard commands * * cxmon (C) 1997-2004 Christian Bauer, Marc Hellwig * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "sysdeps.h" #include #include #include "mon.h" #include "mon_cmd.h" #include "mon_disass.h" #ifndef VERSION #define VERSION "3" #endif /* * range_args = [expression] [[COMMA] expression] END * * Read start address to "adr", end address to "end_adr". * "adr" defaults to '.', "end_adr" defaults to '.'+def_range * * true: OK, false: Error */ static bool range_args(uintptr *adr, uintptr *end_adr, uint32 def_range) { *adr = mon_dot_address; *end_adr = mon_dot_address + def_range; if (mon_token == T_END) return true; else { if (!mon_expression(adr)) return false; *end_adr = *adr + def_range; if (mon_token == T_END) return true; else { if (mon_token == T_COMMA) mon_get_token(); if (!mon_expression(end_adr)) return false; return mon_token == T_END; } } } /* * byte_string = (expression | STRING) {COMMA (expression | STRING)} END */ static bool byte_string(uint8 *&str, uintptr &len) { uintptr value; static const int GRANULARITY = 16; // must be a power of 2 str = NULL; len = 0; goto start; for (;;) { if (mon_token == T_COMMA) { mon_get_token(); start: if (mon_token == T_STRING) { unsigned n = strlen(mon_string); str = (uint8 *)realloc(str, (len + n - 1 + GRANULARITY) & ~(GRANULARITY - 1)); assert(str != NULL); memcpy(str + len, mon_string, n); len += n; mon_get_token(); } else if (mon_expression(&value)) { str = (uint8 *)realloc(str, (len + GRANULARITY) & ~(GRANULARITY - 1)); assert(str != NULL); str[len] = value; len++; } else { if (str) free(str); return false; } } else if (mon_token == T_END) { return true; } else { mon_error("',' expected"); if (str) free(str); return false; } } } /* * Convert character to printable character */ static inline uint8 char2print(uint8 c) { return (c >= 0x20 && c <= 0x7e) ? c : '.'; } /* * Show version * ver */ void version(void) { fprintf(monout, "cxmon V" VERSION "\n"); } /* * Redirect output * o [file] */ void redir_output(void) { // Close old file if (monout != monerr) { fclose(monout); monout = monerr; return; } // No argument given? if (mon_token == T_END) return; // Otherwise open file if (mon_token == T_STRING) { mon_get_token(); if (mon_token != T_END) { mon_error("Too many arguments"); return; } if (!(monout = fopen(mon_string, "w"))) mon_error("Unable to open file"); } else mon_error("'\"' around file name expected"); } /* * Compute and display expression * ? expression */ void print_expr(void) { uintptr val; if (!mon_expression(&val)) return; if (mon_token != T_END) { mon_error("Too many arguments"); return; } if (val > 0x7fffffff) { fprintf(monout, "Hex unsigned: $%08x\n" "Hex signed : -$%08x\n" "Dec unsigned: %u\n" "Dec signed : %d\n", val, -val, val, val); fprintf(monout, "Char : '%c%c%c%c'\n", char2print(val >> 24), char2print(val >> 16), char2print(val >> 8), char2print(val)); } else { fprintf(monout, "Hex : $%08x\n" "Dec : %d\n", val, val); fprintf(monout, "Char: '%c%c%c%c'\n", char2print(val >> 24), char2print(val >> 16), char2print(val >> 8), char2print(val)); } } /* * Execute shell command * \ "command" */ void shell_command(void) { if (mon_token != T_STRING) { mon_error("'\"' around command expected"); return; } mon_get_token(); if (mon_token != T_END) { mon_error("Too many arguments"); return; } system(mon_string); } /* * Memory dump * m [start [end]] */ #define MEMDUMP_BPL 16 // Bytes per line void memory_dump(void) { uintptr adr, end_adr; uint8 mem[MEMDUMP_BPL + 1]; mem[MEMDUMP_BPL] = 0; if (!range_args(&adr, &end_adr, 16 * MEMDUMP_BPL - 1)) // 16 lines unless end address specified return; while (adr <= end_adr && !mon_aborted()) { fprintf(monout, "%0*lx:", int(2 * sizeof(adr)), mon_use_real_mem ? adr: adr % mon_mem_size); for (int i=0; i>=1, i++) str[i] = (b & m) ? '*' : '.'; fprintf(monout, " '%s'\n", str); adr++; } mon_dot_address = adr; } /* * Add Break Point */ void break_point_add(void) { uintptr address; if (mon_token == T_END || !mon_expression(&address)) { mon_error("Expect break point in hexadecimal."); return; } if (mon_token != T_END) { mon_error("Too many arguments"); return; } mon_add_break_point(address); } bool validate_index(uintptr *index_ptr, const BREAK_POINT_SET& break_point_set) { if (mon_token == T_END || !mon_expression(index_ptr)) { mon_error("Expect index number of break point in hexadecimal.\n"); return false; } if (mon_token != T_END) { mon_error("Too many arguments"); return false; } if (*index_ptr > break_point_set.size()) { mon_error("Illegal index number!"); return false; } return true; } /* * Remove Break Point */ void break_point_remove(void) { uintptr index; if (!validate_index(&index, active_break_points)) return; if (0 == index) { active_break_points.clear(); printf("Removed all break points!\n"); return; } BREAK_POINT_SET::iterator it = active_break_points.begin(); std::advance(it, index - 1); // Remove break point printf("Removed break point %4x at address %08lx\n", index, *it); active_break_points.erase(it); } /* * Disable Break Point */ void break_point_disable(void) { uintptr index; if (!validate_index(&index, active_break_points)) return; if (0 == index) { for (BREAK_POINT_SET::iterator it = active_break_points.begin(); it != active_break_points.end(); it++) disabled_break_points.insert(*it); active_break_points.clear(); printf("Disabled all break points!\n"); return; } BREAK_POINT_SET::iterator it = active_break_points.begin(); std::advance(it, index - 1); // Add to disable break points printf("Disabled break point %4x at address %08lx\n", index, *it); disabled_break_points.insert(*it); // Remove break point active_break_points.erase(it); } /* * Enable Break Point */ void break_point_enable(void) { uintptr index; if (!validate_index(&index, disabled_break_points)) return; if (0 == index) { active_break_points.insert(disabled_break_points.begin(), disabled_break_points.end()); disabled_break_points.clear(); printf("Enabled all break points!\n"); return; } BREAK_POINT_SET::iterator it = disabled_break_points.begin(); std::advance(it, index - 1); // Add to active break points printf("Disabled break point %4x at address %08lx\n", index, *it); active_break_points.insert(*it); // Remove break point disabled_break_points.erase(it); } /* * List all Active Break Points */ void break_point_info(void) { if (mon_token != T_END) { mon_error("Too many arguments"); return; } BREAK_POINT_SET::iterator it; if (!active_break_points.empty()) { int pos = 1; printf(STR_ACTIVE_BREAK_POINTS); for (it = active_break_points.begin(); it != active_break_points.end(); it++) printf("\tBreak point %4x at address %08lx\n", pos++, *it); } if (!disabled_break_points.empty()) { putchar('\n'); printf(STR_DISABLED_BREAK_POINTS); int pos = 1; for (it = disabled_break_points.begin(); it != disabled_break_points.end(); it++) printf("\tBreak point %4x at address %08lx\n", pos++, *it); } } /* * Save all Active Break Points to a file */ void break_point_save(void) { if (mon_token == T_END) { mon_error("Missing file name"); return; } if (mon_token != T_STRING) { mon_error("'\"' around file name expected"); return; } mon_get_token(); if (mon_token != T_END) { mon_error("Too many arguments"); return; } FILE *file; if (!(file = fopen(mon_string, "w"))) { mon_error("Unable to create file"); return; } BREAK_POINT_SET::iterator it; fprintf(file, STR_ACTIVE_BREAK_POINTS); for (it = active_break_points.begin(); it != active_break_points.end(); it++) fprintf(file, "%x\n", *it); fprintf(file, STR_DISABLED_BREAK_POINTS); for (it = disabled_break_points.begin(); it != disabled_break_points.end(); it++) fprintf(file, "%x\n", *it); fclose(file); } /* * Load Break Point from a file */ void break_point_load(void) { if (mon_token == T_END) { mon_error("Missing file name"); return; } if (mon_token != T_STRING) { mon_error("'\"' around file name expected"); return; } mon_get_token(); if (mon_token != T_END) { mon_error("Too many arguments"); return; } // load from file mon_load_break_point(mon_string); } /* * Disassemble * d [start [end]] * d65 [start [end]] * d68 [start [end]] * d80 [start [end]] * d86 [start [end]] * d8086 [start [end]] */ enum CPUType { CPU_PPC, CPU_6502, CPU_680x0, CPU_Z80, CPU_80x86_32, CPU_80x86_16, CPU_x86_64 }; static void disassemble(CPUType type) { uintptr adr, end_adr; if (!range_args(&adr, &end_adr, 16 * 4 - 1)) // 16 lines unless end address specified return; switch (type) { case CPU_PPC: while (adr <= end_adr && !mon_aborted()) { uint32 w = mon_read_word(adr); fprintf(monout, "%0*lx: %08x\t", int(2 * sizeof(adr)), mon_use_real_mem ? adr : adr % mon_mem_size, w); disass_ppc(monout, mon_use_real_mem ? adr : adr % mon_mem_size, w); adr += 4; } break; case CPU_6502: while (adr <= end_adr && !mon_aborted()) { uint8 op = mon_read_byte(adr); uint8 lo = mon_read_byte(adr + 1); uint8 hi = mon_read_byte(adr + 2); fprintf(monout, "%0*lx: ", int(2 * sizeof(adr)), mon_use_real_mem ? adr : adr % mon_mem_size); adr += disass_6502(monout, mon_use_real_mem ? adr : adr % mon_mem_size, op, lo, hi); } break; case CPU_680x0: while (adr <= end_adr && !mon_aborted()) { fprintf(monout, "%0*lx: ", int(2 * sizeof(adr)), mon_use_real_mem ? adr : adr % mon_mem_size); adr += disass_68k(monout, mon_use_real_mem ? adr : adr % mon_mem_size); } break; case CPU_Z80: while (adr <= end_adr && !mon_aborted()) { fprintf(monout, "%0*lx: ", int(2 * sizeof(adr)), mon_use_real_mem ? adr : adr % mon_mem_size); adr += disass_z80(monout, mon_use_real_mem ? adr : adr % mon_mem_size); } break; case CPU_x86_64: while (adr <= end_adr && !mon_aborted()) { fprintf(monout, "%0*lx: ", int(2 * sizeof(adr)), mon_use_real_mem ? adr : adr % mon_mem_size); adr += disass_x86(monout, mon_use_real_mem ? adr : adr % mon_mem_size, 64); } break; case CPU_80x86_32: while (adr <= end_adr && !mon_aborted()) { fprintf(monout, "%0*lx: ", int(2 * sizeof(adr)), mon_use_real_mem ? adr : adr % mon_mem_size); adr += disass_x86(monout, mon_use_real_mem ? adr : adr % mon_mem_size, 32); } break; case CPU_80x86_16: while (adr <= end_adr && !mon_aborted()) { fprintf(monout, "%0*lx: ", int(2 * sizeof(adr)), mon_use_real_mem ? adr : adr % mon_mem_size); adr += disass_x86(monout, mon_use_real_mem ? adr : adr % mon_mem_size, 16); } } mon_dot_address = adr; } void disassemble_ppc(void) { disassemble(CPU_PPC); } void disassemble_6502(void) { disassemble(CPU_6502); } void disassemble_680x0(void) { disassemble(CPU_680x0); } void disassemble_z80(void) { disassemble(CPU_Z80); } void disassemble_80x86_32(void) { disassemble(CPU_80x86_32); } void disassemble_80x86_16(void) { disassemble(CPU_80x86_16); } void disassemble_x86_64(void) { disassemble(CPU_x86_64); } /* * Modify memory * : addr bytestring */ void modify(void) { uintptr adr, len, src_adr = 0; uint8 *str; if (!mon_expression(&adr)) return; if (!byte_string(str, len)) return; while (src_adr < len) mon_write_byte(adr++, str[src_adr++]); mon_dot_address = adr; free(str); } /* * Fill * f start end bytestring */ void fill(void) { uintptr adr, end_adr, len, src_adr = 0; uint8 *str; if (!mon_expression(&adr)) return; if (!mon_expression(&end_adr)) return; if (!byte_string(str, len)) return; while (adr <= end_adr) mon_write_byte(adr++, str[src_adr++ % len]); free(str); } /* * Transfer memory * t start end dest */ void transfer(void) { uintptr adr, end_adr, dest; int num; if (!mon_expression(&adr)) return; if (!mon_expression(&end_adr)) return; if (!mon_expression(&dest)) return; if (mon_token != T_END) { mon_error("Too many arguments"); return; } num = end_adr - adr + 1; if (dest < adr) for (int i=0; i