--- uae/src/debug.c 2018/04/24 16:44:45 1.1.1.5 +++ uae/src/debug.c 2018/04/24 17:16:29 1.1.1.13 @@ -13,33 +13,48 @@ #include #include -#include "config.h" #include "options.h" -#include "threaddep/penguin.h" +#include "threaddep/thread.h" #include "uae.h" #include "memory.h" #include "custom.h" -#include "readcpu.h" #include "newcpu.h" +#include "cpu_prefetch.h" #include "debug.h" #include "cia.h" #include "xwin.h" #include "gui.h" - -static int debugger_active = 0; -static uaecptr skipaddr; +#include "identify.h" +#include "disk.h" +#include "autoconf.h" + +#define console_out printf +#define console_flush() fflush (stdout) +#define console_get(BUF, COUNT) fgets (BUF, COUNT, stdin) + +static int debugger_active; +static uaecptr skipaddr_start, skipaddr_end; +static int skipaddr_doskip; +static uae_u32 skipins; static int do_skip; -int debugging = 0; +static int debug_rewind; +static int memwatch_enabled, memwatch_triggered; +int debugging; +int exception_debugging; + +static FILE *logfile; void activate_debugger (void) { + if (logfile) + fclose (logfile); + logfile = 0; do_skip = 0; if (debugger_active) return; debugger_active = 1; - regs.spcflags |= SPCFLAG_BRK; + set_special (SPCFLAG_BRK); debugging = 1; - /* use_debugger = 1; */ } int firsthist = 0; @@ -51,18 +66,66 @@ union flagu historyf[MAX_HIST]; uaecptr history[MAX_HIST]; #endif +static char help[] = { + " HELP for UAE Debugger\n" + " -----------------------\n\n" + " g [
] Start execution at the current address or
\n" + " c Dump state of the CIA, disk drives and custom registers\n" + " r Dump state of the CPU\n" + " m
[] Memory dump starting at
\n" + " d
[] Disassembly starting at
\n" + " t [instructions] Step one or more instructions\n" + " z Step through one instruction - useful for JSR, DBRA etc\n" + " f Step forward until PC in RAM\n" + " f
Add/remove breakpoint\n" + " fi Step forward until PC points to RTS/RTD or RTE\n" + " fi Step forward until PC points to \n" + " fl List breakpoints\n" + " fd Remove all breakpoints\n" + " f Step forward until <= PC <= \n" + " e Dump contents of all custom registers\n" + " i Dump contents of interrupt and trap vectors\n" + " o <1|2|addr> []View memory as Copper instructions\n" + " O Display bitplane offsets\n" + " O Offset a bitplane\n" + " H Show PC history instructions\n" + " M Search for *Tracker sound modules\n" + " C Search for values like energy or lifes in games\n" + " W
Write into Amiga memory\n" + " w
[]\n" + " Add/remove memory watchpoints\n" + " wd Enable illegal access logger\n" + " S Save a block of Amiga memory\n" + " s / [] []\n" + " Search for string/bytes\n" + " T Show exec tasks and their PCs\n" + " h,? Show this help page\n" + " q Quit the emulator. You don't want to use this command.\n\n" +}; + +static void debug_help (void) +{ + console_out (help); +} + + + static void ignore_ws (char **c) { while (**c && isspace(**c)) (*c)++; } +static uae_u32 readint (char **c); static uae_u32 readhex (char **c) { uae_u32 val = 0; char nc; ignore_ws (c); - + if (**c == '!' || **c == '_') { + (*c)++; + return readint (c); + } while (isxdigit(nc = **c)) { (*c)++; val *= 16; @@ -76,6 +139,31 @@ static uae_u32 readhex (char **c) return val; } +static uae_u32 readint (char **c) +{ + uae_u32 val = 0; + char nc; + int negative = 0; + + ignore_ws (c); + if (**c == '$') { + (*c)++; + return readhex (c); + } + if (**c == '0' && toupper((*c)[1]) == 'X') { + (*c)+= 2; + return readhex (c); + } + if (**c == '-') + negative = 1, (*c)++; + while (isdigit(nc = **c)) { + (*c)++; + val *= 10; + val += nc - '0'; + } + return val * (negative ? -1 : 1); +} + static char next_char( char **c) { ignore_ws (c); @@ -88,16 +176,51 @@ static int more_params (char **c) return (**c) != 0; } +static uae_u32 nextaddr (uae_u32 addr) +{ + if (addr == 0xffffffff) { + if (currprefs.bogomem_size) + return 0xc00000 + currprefs.bogomem_size; + if (currprefs.fastmem_size) + return 0x200000 + currprefs.fastmem_size; + return currprefs.chipmem_size; + } + if (addr == currprefs.chipmem_size) { + if (currprefs.fastmem_size) + return 0x200000; + else if (currprefs.bogomem_size) + return 0xc00000; + return 0xffffffff; + } + if (addr == 0x200000 + currprefs.fastmem_size) { + if (currprefs.bogomem_size) + return 0xc00000; + return 0xffffffff; + } + if (addr == 0xc00000 + currprefs.bogomem_size) + return 0xffffffff; + return addr + 1; +} + static void dumpmem (uaecptr addr, uaecptr *nxmem, int lines) { - broken_in = 0; - for (;lines-- && !broken_in;) { + char line[80]; + int cols = 8; + for (;lines--;) { int i; - printf ("%08lx ", addr); - for (i = 0; i < 16; i++) { - printf ("%04x ", get_word(addr)); addr += 2; + sprintf (line, "%08lx ", addr); + for (i = 0; i < cols; i++) { + uae_u8 b1 = get_byte (addr + 0); + uae_u8 b2 = get_byte (addr + 1); + addr += 2; + sprintf (line + 9 + i * 5, "%02x%02x ", b1, b2); + line[9 + cols * 5 + 1 + i * 2 + 0] = b1 >= 32 && b1 < 127 ? b1 : '.'; + line[9 + cols * 5 + 1 + i * 2 + 1] = b2 >= 32 && b2 < 127 ? b2 : '.'; } - printf ("\n"); + line[9 + cols * 5] = ' '; + line[9 + cols * 5 + 1 + 2 * cols] = 0; + console_out (line); + console_out ("\n"); } *nxmem = addr; } @@ -108,7 +231,7 @@ static void foundmod (uae_u32 ptr, char uae_u8 *ptr2 = chipmemory + ptr; int i,length; - printf ("Found possible %s module at 0x%lx.\n", type, ptr); + console_out ("Found possible %s module at 0x%lx.\n", type, ptr); memcpy (name, ptr2, 20); name[20] = '\0'; @@ -124,8 +247,8 @@ static void foundmod (uae_u32 ptr, char ptr2 += 0x2A; for (i = 0; i < 31; i++, ptr2 += 30) length += 2*((ptr2[0]<<8)+ptr2[1]); - - printf ("Name \"%s\", Length 0x%lx bytes.\n", name, length); + + console_out ("Name \"%s\", Length 0x%lx bytes.\n", name, length); } static void modulesearch (void) @@ -143,16 +266,16 @@ static void modulesearch (void) foundmod (ptr - 0x438, "Startrekker"); if (strncmp ((char *)p, "SMOD", 4) == 0) { - printf ("Found possible FutureComposer 1.3 module at 0x%lx, length unknown.\n", ptr); + console_out ("Found possible FutureComposer 1.3 module at 0x%lx, length unknown.\n", ptr); } if (strncmp ((char *)p, "FC14", 4) == 0) { - printf ("Found possible FutureComposer 1.4 module at 0x%lx, length unknown.\n", ptr); + console_out ("Found possible FutureComposer 1.4 module at 0x%lx, length unknown.\n", ptr); } if (p[0] == 0x48 && p[1] == 0xe7 && p[4] == 0x61 && p[5] == 0 && p[8] == 0x4c && p[9] == 0xdf && p[12] == 0x4e && p[13] == 0x75 && p[14] == 0x48 && p[15] == 0xe7 && p[18] == 0x61 && p[19] == 0 && p[22] == 0x4c && p[23] == 0xdf && p[26] == 0x4e && p[27] == 0x75) { - printf ("Found possible Whittaker module at 0x%lx, length unknown.\n", ptr); + console_out ("Found possible Whittaker module at 0x%lx, length unknown.\n", ptr); } if (p[4] == 0x41 && p[5] == 0xFA) { int i; @@ -164,14 +287,137 @@ static void modulesearch (void) uae_u8 *p2 = p + i + 4; for (i = 0; i < 0x30; i += 2) if (p2[i] == 0xD1 && p2[i + 1] == 0xFA) { - printf ("Found possible MarkII module at %lx, length unknown.\n", ptr); + console_out ("Found possible MarkII module at %lx, length unknown.\n", ptr); } } - } } } +static void dump_vectors (void) +{ + int i = 0, j = 0; + + while (int_labels[i].name || trap_labels[j].name) { + if (int_labels[i].name) { + console_out ("$%08X: %s \t $%08X\t", int_labels[i].adr + regs.vbr, + int_labels[i].name, get_long (int_labels[i].adr + (int_labels[i].adr == 4 ? 0 : regs.vbr))); + i++; + } else { + console_out ("\t\t\t\t"); + } + if (trap_labels[j].name) { + console_out("$%08X: %s \t $%08X", trap_labels[j].adr + regs.vbr, + trap_labels[j].name, get_long (trap_labels[j].adr + regs.vbr)); + j++; + } + console_out ("\n"); + } +} + +static void disassemble_wait (FILE *file, unsigned long insn) +{ + int vp, hp, ve, he, bfd, v_mask, h_mask; + + vp = (insn & 0xff000000) >> 24; + hp = (insn & 0x00fe0000) >> 16; + ve = (insn & 0x00007f00) >> 8; + he = (insn & 0x000000fe); + bfd = (insn & 0x00008000) >> 15; + + /* bit15 can never be masked out*/ + v_mask = vp & (ve | 0x80); + h_mask = hp & he; + if (v_mask > 0) { + console_out ("vpos "); + if (ve != 0x7f) { + console_out ("& 0x%02x ", ve); + } + console_out (">= 0x%02x", v_mask); + } + if (he > 0) { + if (v_mask > 0) { + console_out (" and"); + } + console_out (" hpos "); + if (he != 0xfe) { + console_out ("& 0x%02x ", he); + } + console_out (">= 0x%02x", h_mask); + } else { + console_out (", ignore horizontal"); + } + + console_out (".\n \t; VP %02x, VE %02x; HP %02x, HE %02x; BFD %d\n", + vp, ve, hp, he, bfd); +} + +/* simple decode copper by Mark Cox */ +static void decode_copper_insn (FILE* file, unsigned long insn, unsigned long addr) +{ + uae_u32 insn_type = insn & 0x00010001; + int hpos, vpos; + char record[] = " "; + if (find_copper_record (addr, &hpos, &vpos)) { + sprintf (record, " [%03x %03x]", vpos, hpos); + } + + console_out ("%08lx: %04lx %04lx%s\t; ", addr, insn >> 16, insn & 0xFFFF, record); + + switch (insn_type) { + case 0x00010000: /* WAIT insn */ + console_out ("Wait for "); + disassemble_wait (file, insn); + + if (insn == 0xfffffffe) + console_out (" \t; End of Copperlist\n"); + + break; + + case 0x00010001: /* SKIP insn */ + console_out ("Skip if "); + disassemble_wait (file, insn); + break; + + case 0x00000000: + case 0x00000001: /* MOVE insn */ + { + int addr = (insn >> 16) & 0x1fe; + int i = 0; + while (custd[i].name) { + if (custd[i].adr == addr + 0xdff000) + break; + i++; + } + if (custd[i].name) + console_out ("%s := 0x%04lx\n", custd[i].name, insn & 0xffff); + else + console_out ("%04x := 0x%04lx\n", addr, insn & 0xffff); + } + break; + + default: + abort (); + } + +} + + +static uaecptr decode_copperlist (FILE* file, uaecptr address, int nolines) +{ + uae_u32 insn; + while (nolines-- > 0) { + insn = get_long (address); + decode_copper_insn (file, insn, address); + address += 4; + } + return address; + /* You may wonder why I don't stop this at the end of the copperlist? + * Well, often nice things are hidden at the end and it is debatable the actual + * values that mean the end of the copperlist */ +} + + /* cheat-search by Holger Jakob */ static void cheatsearch (char **c) { @@ -183,18 +429,9 @@ static void cheatsearch (char **c) uae_u32 count = 0; uae_u32 fcount = 0; uae_u32 full = 0; - char nc; ignore_ws (c); - - while (isxdigit (nc = **c)) { - (*c)++; - val *= 10; - nc = toupper (nc); - if (isdigit (nc)) { - val += nc - '0'; - } - } + val = readhex (c); if (vlist == NULL) { vlist = malloc (256*4); if (vlist != 0) { @@ -209,270 +446,985 @@ static void cheatsearch (char **c) { if (count < 255) { vlist[count++]=ptr; - printf ("%08x: %x%x%x%x\n",ptr,p[0],p[1],p[2],p[3]); + console_out ("%08x: %x%x%x%x\n",ptr,p[0],p[1],p[2],p[3]); } else full = 1; } } - printf ("Found %d possible addresses with %d\n",count,val); - printf ("Now continue with 'g' and use 'C' with a different value\n"); + console_out ("Found %d possible addresses with %d\n",count,val); + console_out ("Now continue with 'g' and use 'C' with a different value\n"); } } else { for (count = 0; count<255; count++) { if (p[vlist[count]+3] == (val & 0xff) - && p[vlist[count]+2] == (val>>8 & 0xff) + && p[vlist[count]+2] == (val>>8 & 0xff) && p[vlist[count]+1] == (val>>16 & 0xff) && p[vlist[count]] == (val>>24 & 0xff)) { fcount++; - printf ("%08x: %x%x%x%x\n", vlist[count], p[vlist[count]], + console_out ("%08x: %x%x%x%x\n", vlist[count], p[vlist[count]], p[vlist[count]+1], p[vlist[count]+2], p[vlist[count]+3]); } } - printf ("%d hits of %d found\n",fcount,val); + console_out ("%d hits of %d found\n",fcount,val); free (vlist); vlist = NULL; } } -static void writeintomem (char **c) +#define BREAKPOINT_TOTAL 8 +struct breakpoint_node { + uaecptr addr; + int enabled; +}; +static struct breakpoint_node bpnodes[BREAKPOINT_TOTAL]; + +static addrbank **debug_mem_banks; +#define MEMWATCH_TOTAL 4 +struct memwatch_node { + uaecptr addr; + int size; + int rw; + uae_u32 val; + int val_enabled; + uae_u32 modval; + int modval_written; +}; +static struct memwatch_node mwnodes[MEMWATCH_TOTAL]; +static struct memwatch_node mwhit; + +static uae_u8 *illgdebug; +static int illgdebug_break; +extern int cdtv_enabled, cd32_enabled; + +static void illg_init (void) { - uae_u8 *p = get_real_address (0); - uae_u32 addr = 0; - uae_u32 val = 0; - char nc; + int i; - ignore_ws(c); - while (isxdigit(nc = **c)) { - (*c)++; - addr *= 16; - nc = toupper(nc); - if (isdigit(nc)) { - addr += nc - '0'; - } else { - addr += nc - 'A' + 10; + free (illgdebug); + illgdebug = xmalloc (0x1000000); + if (!illgdebug) + return; + memset (illgdebug, 3, 0x1000000); + memset (illgdebug, 0, currprefs.chipmem_size); + memset (illgdebug + 0xc00000, 0, currprefs.bogomem_size); + memset (illgdebug + 0x200000, 0, currprefs.fastmem_size); + i = 0; + while (custd[i].name) { + int rw = custd[i].rw; + illgdebug[custd[i].adr] = rw; + illgdebug[custd[i].adr + 1] = rw; + i++; + } + for (i = 0; i < 16; i++) { /* CIAs */ + if (i == 11) + continue; + illgdebug[0xbfe001 + i * 0x100] = 0; + illgdebug[0xbfd000 + i * 0x100] = 0; + } + memset (illgdebug + 0xf80000, 1, 512 * 1024); /* KS ROM */ + memset (illgdebug + 0xdc0000, 0, 0x3f); /* clock */ + if (cloanto_rom) + memset (illgdebug + 0xe00000, 1, 512 * 1024); +#ifdef FILESYS + if (nr_units (currprefs.mountinfo) > 0) /* filesys "rom" */ + memset (illgdebug + RTAREA_BASE, 1, 0x10000); +#endif +} + +/* add special custom register check here */ +static void illg_debug_check (uaecptr addr, int rw, int size, uae_u32 val) +{ + return; +} + +static void illg_debug_do (uaecptr addr, int rw, int size, uae_u32 val) +{ + uae_u8 mask; + uae_u32 pc = m68k_getpc (); + char rws = rw ? 'W' : 'R'; + int i; + + for (i = size - 1; i >= 0; i--) { + uae_u8 v = val >> (i * 8); + uae_u32 ad = addr + i; + if (ad >= 0x1000000) + mask = 3; + else + mask = illgdebug[ad]; + if (!mask) + continue; + if (mask & 0x80) { + illg_debug_check (ad, rw, size, val); + } else if ((mask & 3) == 3) { + if (rw) + write_log ("RW: %08.8X=%02.2X %c PC=%08.8X\n", ad, v, rws, pc); + else + write_log ("RW: %08.8X %c PC=%08.8X\n", ad, rws, pc); + if (illgdebug_break) + activate_debugger (); + } else if ((mask & 1) && rw) { + write_log ("RO: %08.8X=%02.2X %c PC=%08.8X\n", ad, v, rws, pc); + if (illgdebug_break) + activate_debugger (); + } else if ((mask & 2) && !rw) { + write_log ("WO: %08.8X %c PC=%08.8X\n", ad, rws, pc); + if (illgdebug_break) + activate_debugger (); } } - ignore_ws(c); - while (isxdigit(nc = **c)) { - (*c)++; - val *= 10; - nc = toupper(nc); - if (isdigit(nc)) { - val += nc - '0'; +} + +static int debug_mem_off (uaecptr addr) +{ + return (munge24 (addr) >> 16) & 0xff; +} + +static void memwatch_func (uaecptr addr, int rw, int size, uae_u32 val) +{ + int i, brk; + + if (illgdebug) + illg_debug_do (addr, rw, size, val); + addr = munge24 (addr); + for (i = 0; i < MEMWATCH_TOTAL; i++) { + uaecptr addr2 = mwnodes[i].addr; + uaecptr addr3 = addr2 + mwnodes[i].size; + int rw2 = mwnodes[i].rw; + + brk = 0; + if (mwnodes[i].size == 0) + continue; + if (mwnodes[i].val_enabled && mwnodes[i].val != val) + continue; + if (rw != rw2 && rw2 < 2) + continue; + if (addr >= addr2 && addr < addr3) + brk = 1; + if (!brk && size == 2 && (addr + 1 >= addr2 && addr + 1 < addr3)) + brk = 1; + if (!brk && size == 4 && ((addr + 2 >= addr2 && addr + 2 < addr3) || (addr + 3 >= addr2 && addr + 3 < addr3))) + brk = 1; + if (brk && mwnodes[i].modval_written) { + if (!rw) { + brk = 0; + } else if (mwnodes[i].modval_written == 1) { + mwnodes[i].modval_written = 2; + mwnodes[i].modval = val; + brk = 0; + } else if (mwnodes[i].modval == val) { + brk = 0; + } + } + if (brk) { + mwhit.addr = addr; + mwhit.rw = rw; + mwhit.size = size; + mwhit.val = 0; + if (mwhit.rw) + mwhit.val = val; + memwatch_triggered = i + 1; + debugging = 1; + set_special (SPCFLAG_BRK); + break; } } +} - if (addr < allocated_chipmem) { - p[addr] = val>>24 & 0xff; - p[addr+1] = val>>16 & 0xff; - p[addr+2] = val>>8 & 0xff; - p[addr+3] = val & 0xff; - printf("Wrote %d at %08x\n",val,addr); - } else - printf("Invalid address %08x\n",addr); +static uae_u32 REGPARAM2 debug_lget (uaecptr addr) +{ + int off = debug_mem_off (addr); + uae_u32 v; + v = debug_mem_banks[off]->lget(addr); + memwatch_func (addr, 0, 4, v); + return v; } - -void debug (void) +static uae_u32 REGPARAM2 debug_wget (uaecptr addr) { - char input[80]; - uaecptr nextpc,nxdis,nxmem; + int off = debug_mem_off (addr); + uae_u32 v; + v = debug_mem_banks[off]->wget(addr); + memwatch_func (addr, 0, 2, v); + return v; +} +static uae_u32 REGPARAM2 debug_bget (uaecptr addr) +{ + int off = debug_mem_off (addr); + uae_u32 v; + v = debug_mem_banks[off]->bget(addr); + memwatch_func (addr, 0, 1, v); + return v; +} +static void REGPARAM2 debug_lput (uaecptr addr, uae_u32 v) +{ + int off = debug_mem_off (addr); + memwatch_func (addr, 1, 4, v); + debug_mem_banks[off]->lput(addr, v); +} +static void REGPARAM2 debug_wput (uaecptr addr, uae_u32 v) +{ + int off = debug_mem_off (addr); + memwatch_func (addr, 1, 2, v); + debug_mem_banks[off]->wput(addr, v); +} +static void REGPARAM2 debug_bput (uaecptr addr, uae_u32 v) +{ + int off = debug_mem_off (addr); + memwatch_func (addr, 1, 1, v); + debug_mem_banks[off]->bput(addr, v); +} +static int REGPARAM2 debug_check (uaecptr addr, uae_u32 size) +{ + return debug_mem_banks[munge24 (addr) >> 16]->check (addr, size); +} +static uae_u8 *REGPARAM2 debug_xlate (uaecptr addr) +{ + return debug_mem_banks[munge24 (addr) >> 16]->xlateaddr (addr); +} - bogusframe = 1; +static void deinitialize_memwatch (void) +{ + int i; + addrbank *a1, *a2; - if (do_skip && (m68k_getpc() != skipaddr/* || regs.a[0] != 0x1e558*/)) { - regs.spcflags |= SPCFLAG_BRK; + if (!memwatch_enabled) return; + for (i = 0; i < 256; i++) { + a1 = debug_mem_banks[i]; + a2 = mem_banks[i]; + memcpy (a2, a1, sizeof (addrbank)); + free (a1); } - do_skip = 0; + free (debug_mem_banks); + debug_mem_banks = 0; + memwatch_enabled = 0; + free (illgdebug); + illgdebug = 0; +} -#ifdef NEED_TO_DEBUG_BADLY - history[lasthist] = regs; - historyf[lasthist] = regflags; -#else - history[lasthist] = m68k_getpc(); -#endif - if (++lasthist == MAX_HIST) lasthist = 0; - if (lasthist == firsthist) { - if (++firsthist == MAX_HIST) firsthist = 0; +static int initialize_memwatch (void) +{ + int i; + addrbank *a1, *a2; + + if (!currprefs.address_space_24) + return 0; + debug_mem_banks = xmalloc (sizeof (addrbank*) * 256); + for (i = 0; i < 256; i++) { + a1 = debug_mem_banks[i] = xmalloc (sizeof (addrbank)); + a2 = mem_banks[i]; + memcpy (a1, a2, sizeof (addrbank)); + } + for (i = 0; i < 256; i++) { + a2 = mem_banks[i]; + a2->bget = debug_bget; + a2->wget = debug_wget; + a2->lget = debug_lget; + a2->bput = debug_bput; + a2->wput = debug_wput; + a2->lput = debug_lput; + a2->check = debug_check; + a2->xlateaddr = debug_xlate; } + memwatch_enabled = 1; + return 1; +} - m68k_dumpstate (&nextpc); - nxdis = nextpc; nxmem = 0; +static void memwatch_dump (int num) +{ + int i; + struct memwatch_node *mwn; + for (i = 0; i < MEMWATCH_TOTAL; i++) { + if ((num >= 0 && num == i) || (num < 0)) { + mwn = &mwnodes[i]; + if (mwn->size == 0) + continue; + console_out ("%d: %08.8X - %08.8X (%d) %s", + i, mwn->addr, mwn->addr + (mwn->size - 1), mwn->size, + mwn->rw == 0 ? "R" : (mwn->rw == 1 ? "W" : "RW")); + if (mwn->val_enabled) + console_out (" =%X", mwn->val); + if (mwn->modval_written) + console_out (" =M"); + console_out("\n"); + } + } +} - for (;;) { - char cmd, *inptr; +static void memwatch (char **c) +{ + int num; + struct memwatch_node *mwn; + char nc; - printf (">"); - fflush (stdout); - if (fgets (input, 80, stdin) == 0) + if (!memwatch_enabled) { + if (!initialize_memwatch ()) { + console_out ("Memwatch breakpoints require 24-bit address space\n"); return; - inptr = input; - cmd = next_char (&inptr); - switch (cmd) { - case 'c': dumpcia (); dumpcustom (); break; - case 'r': m68k_dumpstate (&nextpc); break; - case 'M': modulesearch (); break; - case 'C': cheatsearch (&inptr); break; - case 'W': writeintomem (&inptr); break; - case 'S': - { - uae_u8 *memp; - uae_u32 src, len; - char *name; - FILE *fp; - - if (!more_params (&inptr)) - goto S_argh; - - name = inptr; - while (*inptr != '\0' && !isspace (*inptr)) - inptr++; - if (!isspace (*inptr)) - goto S_argh; - - *inptr = '\0'; - inptr++; - if (!more_params (&inptr)) - goto S_argh; - src = readhex (&inptr); - if (!more_params (&inptr)) - goto S_argh; - len = readhex (&inptr); - if (! valid_address (src, len)) { - printf ("Invalid memory block\n"); - break; + } + console_out ("Memwatch breakpoints enabled\n"); + } + + ignore_ws (c); + if (!more_params (c)) { + memwatch_dump (-1); + return; + } + nc = next_char (c); + if (nc == '-') { + deinitialize_memwatch (); + console_out ("Memwatch breakpoints disabled\n"); + return; + } + if (nc == 'd') { + if (illgdebug) { + ignore_ws (c); + if (more_params (c)) { + uae_u32 addr = readhex (c); + uae_u32 len = 1; + if (more_params (c)) + len = readhex (c); + write_log ("cleared logging addresses %08.8X - %08.8X\n", addr, addr + len); + while (len > 0) { + addr &= 0xffffff; + illgdebug[addr] = 0; + addr++; + len--; } - memp = get_real_address (src); - fp = fopen (name, "w"); - if (fp == NULL) { - printf ("Couldn't open file\n"); - break; + } + } else { + illg_init (); + console_out ("Illegal memory access logging enabled\n"); + ignore_ws (c); + illgdebug_break = 0; + if (more_params (c)) + illgdebug_break = 1; + } + return; + } + num = nc - '0'; + if (num < 0 || num >= MEMWATCH_TOTAL) + return; + mwn = &mwnodes[num]; + mwn->size = 0; + ignore_ws (c); + if (!more_params (c)) { + console_out ("Memwatch %d removed\n", num); + return; + } + mwn->addr = readhex (c); + mwn->size = 1; + mwn->rw = 2; + mwn->val_enabled = 0; + mwn->modval_written = 0; + ignore_ws (c); + if (more_params (c)) { + mwn->size = readhex (c); + ignore_ws (c); + if (more_params (c)) { + char nc = toupper (next_char (c)); + if (nc == 'W') + mwn->rw = 1; + else if (nc == 'R' && toupper(**c) != 'W') + mwn->rw = 0; + else if (nc == 'R' && toupper(**c) == 'W') + next_char (c); + ignore_ws (c); + if (more_params (c)) { + if (toupper(**c) == 'M') { + mwn->modval_written = 1; + } else { + mwn->val = readhex (c); + mwn->val_enabled = 1; } - if (fwrite (memp, 1, len, fp) != len) { - printf ("Error writing file\n"); + } + } + } + memwatch_dump (num); +} + +static void writeintomem (char **c) +{ + uae_u32 addr = 0; + uae_u32 val = 0; + char cc; + + ignore_ws(c); + addr = readhex (c); + ignore_ws(c); + val = readhex (c); + if (val > 0xffff) { + put_long (addr, val); + cc = 'L'; + } else if (val > 0xff) { + put_word (addr, val); + cc = 'W'; + } else { + put_byte (addr, val); + cc = 'B'; + } + console_out ("Wrote %x (%u) at %08x.%c\n", val, val, addr, cc); +} + +static void show_exec_tasks (void) +{ + uaecptr execbase = get_long (4); + uaecptr taskready = get_long (execbase + 406); + uaecptr taskwait = get_long (execbase + 420); + uaecptr node, end; + console_out ("execbase at 0x%08lx\n", (unsigned long) execbase); + console_out ("Current:\n"); + node = get_long (execbase + 276); + console_out ("%08lx: %08lx %s\n", node, 0, get_real_address (get_long (node + 10))); + console_out ("Ready:\n"); + node = get_long (taskready); + end = get_long (taskready + 4); + while (node) { + console_out ("%08lx: %08lx %s\n", node, 0, get_real_address (get_long (node + 10))); + node = get_long (node); + } + console_out ("Waiting:\n"); + node = get_long (taskwait); + end = get_long (taskwait + 4); + while (node) { + console_out ("%08lx: %08lx %s\n", node, 0, get_real_address (get_long (node + 10))); + node = get_long (node); + } +} + +static int trace_same_insn_count; +static uae_u8 trace_insn_copy[10]; +static struct regstruct trace_prev_regs; +static uaecptr nextpc; + +static int instruction_breakpoint (char **c) +{ + struct breakpoint_node *bpn; + int i; + + if (more_params (c)) { + char nc = toupper((*c)[0]); + if (nc == 'I') { + next_char (c); + if (more_params (c)) + skipins = readhex (c); + else + skipins = 0x10000; + do_skip = 1; + skipaddr_doskip = 1; + return 1; + } else if (nc == 'D' && (*c)[1] == 0) { + for (i = 0; i < BREAKPOINT_TOTAL; i++) + bpnodes[i].enabled = 0; + console_out ("All breakpoints removed\n"); + return 0; + } else if (nc == 'L') { + int got = 0; + for (i = 0; i < BREAKPOINT_TOTAL; i++) { + bpn = &bpnodes[i]; + if (!bpn->enabled) + continue; + console_out ("%8X ", bpn->addr); + got = 1; + } + if (!got) + console_out ("No breakpoints\n"); + else + console_out ("\n"); + return 0; + } + skipaddr_doskip = 1; + skipaddr_start = readhex (c); + if (more_params (c)) { + skipaddr_end = readhex (c); + } else { + for (i = 0; i < BREAKPOINT_TOTAL; i++) { + bpn = &bpnodes[i]; + if (bpn->enabled && bpn->addr == skipaddr_start) { + bpn->enabled = 0; + console_out ("Breakpoint removed\n"); + skipaddr_start = 0xffffffff; + skipaddr_doskip = 0; + return 0; } - fclose (fp); + } + for (i = 0; i < BREAKPOINT_TOTAL; i++) { + bpn = &bpnodes[i]; + if (bpn->enabled) + continue; + bpn->addr = skipaddr_start; + bpn->enabled = 1; + console_out ("Breakpoint added\n"); + skipaddr_start = 0xffffffff; + skipaddr_doskip = 0; break; + } + return 0; + } + } + if (skipaddr_start == 0xC0DEDBAD) { + trace_same_insn_count = 0; + logfile = fopen ("uae.trace", "w"); + memcpy (trace_insn_copy, regs.pc_p, 10); + memcpy (&trace_prev_regs, ®s, sizeof regs); + } + do_skip = 1; + skipaddr_doskip = -1; + return 1; +} - S_argh: - printf ("S command needs more arguments!\n"); +static void savemem (char **cc) +{ + uae_u8 b; + uae_u32 src, src2, len, len2; + char *name; + FILE *fp; + + if (!more_params (cc)) + goto S_argh; + + name = *cc; + while (**cc != '\0' && !isspace (**cc)) + (*cc)++; + if (!isspace (**cc)) + goto S_argh; + + **cc = '\0'; + (*cc)++; + if (!more_params (cc)) + goto S_argh; + src2 = src = readhex (cc); + if (!more_params (cc)) + goto S_argh; + len2 = len = readhex (cc); + fp = fopen (name, "wb"); + if (fp == NULL) { + console_out ("Couldn't open file '%s'\n", name); + return; + } + while (len > 0) { + b = get_byte (src); + src++; + len--; + if (fwrite (&b, 1, 1, fp) != 1) { + console_out ("Error writing file\n"); + break; + } + } + fclose (fp); + if (len == 0) + console_out ("Wrote %08X - %08X (%d bytes) to '%s'\n", + src2, src2 + len2, len2, name); + return; +S_argh: + console_out ("S-command needs more arguments!\n"); +} + +static void searchmem (char **cc) +{ + int i, sslen, got, val, stringmode; + uae_u8 ss[256]; + uae_u32 addr, endaddr; + char nc; + + got = 0; + sslen = 0; + stringmode = 0; + ignore_ws (cc); + if (**cc == '"') { + stringmode = 1; + (*cc)++; + while (**cc != '"' && **cc != 0) { + ss[sslen++] = tolower (**cc); + (*cc)++; + } + if (**cc != 0) + (*cc)++; + } else { + for (;;) { + if (**cc == 32 || **cc == 0) break; + nc = toupper (next_char (cc)); + if (isspace (nc)) + break; + if (isdigit(nc)) + val = nc - '0'; + else + val = nc - 'A' + 10; + if (val < 0 || val > 15) + return; + val *= 16; + if (**cc == 32 || **cc == 0) + break; + nc = toupper (next_char (cc)); + if (isspace (nc)) + break; + if (isdigit(nc)) + val += nc - '0'; + else + val += nc - 'A' + 10; + if (val < 0 || val > 255) + return; + ss[sslen++] = (uae_u8)val; + } + } + if (sslen == 0) + return; + ignore_ws (cc); + addr = 0; + endaddr = nextaddr (0xffffffff); + if (more_params (cc)) { + addr = readhex (cc); + if (more_params (cc)) + endaddr = readhex (cc); + } + console_out ("Searching from %08x to %08x..\n", addr, endaddr); + while (addr < endaddr && addr != 0xffffffff) { + for (i = 0; i < sslen; i++) { + uae_u8 b = get_byte (addr + i); + if (stringmode) { + if (tolower (b) != ss[i]) + break; + } else { + if (b != ss[i]) + break; } - case 'd': - { - uae_u32 daddr; - int count; - - if (more_params(&inptr)) - daddr = readhex(&inptr); - else - daddr = nxdis; - if (more_params(&inptr)) - count = readhex(&inptr); - else - count = 10; - m68k_disasm(daddr, &nxdis, count); + } + if (i == sslen) { + got++; + console_out (" %08x", addr); + if (got > 100) { + console_out ("\nMore than 100 results, aborting.."); + break; } - break; - case 't': regs.spcflags |= SPCFLAG_BRK; return; - case 'z': - skipaddr = nextpc; - do_skip = 1; - regs.spcflags |= SPCFLAG_BRK; - return; + } + addr = nextaddr (addr); + } + if (!got) + console_out ("nothing found"); + console_out ("\n"); +} + +static void m68k_modify (char **inptr) +{ + char c1, c2; + uae_u32 v; + + c1 = toupper (next_char (inptr)); + if (!more_params (inptr)) + return; + c2 = toupper (next_char (inptr)); + if (c2 < '0' || c2 > '7') + return; + c2 -= '0'; + v = readhex (inptr); + if (c1 == 'A') + regs.regs[8 + c2] = v; + else if (c1 == 'D') + regs.regs[c2] = v; + else if (c1 == 'P' && c2 == 0) + regs.irc = v; + else if (c1 == 'P' && c2 == 1) + regs.ir = v; +} - case 'f': - skipaddr = readhex(&inptr); +static void debug_1 (void) +{ + char input[80]; + uaecptr nxdis,nxmem,nxcopper; + + m68k_dumpstate (stdout, &nextpc); + nxdis = nextpc; nxmem = nxcopper = 0; + + for (;;) { + char cmd, *inptr; + + console_out (">"); + console_flush (); + if (!console_get (input, 80)) + continue; + inptr = input; + cmd = next_char (&inptr); + switch (cmd) { + case 'c': dumpcia (); dumpdisk (); dumpcustom (); break; + case 'i': dump_vectors (); break; + case 'r': if (more_params(&inptr)) + m68k_modify (&inptr); + else + m68k_dumpstate (stdout, &nextpc); + break; + case 'M': modulesearch (); break; + case 'C': cheatsearch (&inptr); break; + case 'W': writeintomem (&inptr); break; + case 'w': memwatch (&inptr); break; + case 'S': savemem (&inptr); break; + case 's': searchmem (&inptr); break; + case 'd': + { + uae_u32 daddr; + int count; + + if (more_params(&inptr)) + daddr = readhex(&inptr); + else + daddr = nxdis; + if (more_params(&inptr)) + count = readhex(&inptr); + else + count = 10; + m68k_disasm (stdout, daddr, &nxdis, count); + } + break; + case 'T': show_exec_tasks (); break; + case 't': + if (more_params (&inptr)) + skipaddr_doskip = readint (&inptr); + if (skipaddr_doskip <= 0 || skipaddr_doskip > 10000) + skipaddr_doskip = 1; + set_special (SPCFLAG_BRK); + exception_debugging = 1; + return; + case 'z': + skipaddr_start = nextpc; + skipaddr_doskip = 1; do_skip = 1; - regs.spcflags |= SPCFLAG_BRK; + exception_debugging = 1; return; - case 'q': uae_quit(); + case 'f': + if (instruction_breakpoint (&inptr)) + return; + break; + + case 'q': uae_quit(); debugger_active = 0; debugging = 0; return; - case 'g': - if (more_params (&inptr)) + case 'g': + if (more_params (&inptr)) { m68k_setpc (readhex (&inptr)); - fill_prefetch_0 (); + fill_prefetch_slow (); + } debugger_active = 0; debugging = 0; + exception_debugging = 0; return; - case 'H': - { - int count; - int temp; + case 'H': + { + int count; + int temp; #ifdef NEED_TO_DEBUG_BADLY - struct regstruct save_regs = regs; - union flagu save_flags = regflags; + struct regstruct save_regs = regs; + union flagu save_flags = regflags; #endif - if (more_params(&inptr)) - count = readhex(&inptr); - else - count = 10; - if (count < 0) - break; - temp = lasthist; - while (count-- > 0 && temp != firsthist) { - if (temp == 0) temp = MAX_HIST-1; else temp--; - } - while (temp != lasthist) { + if (more_params(&inptr)) + count = readhex(&inptr); + else + count = 10; + if (count < 0) + break; + temp = lasthist; + while (count-- > 0 && temp != firsthist) { + if (temp == 0) temp = MAX_HIST-1; else temp--; + } + while (temp != lasthist) { #ifdef NEED_TO_DEBUG_BADLY - regs = history[temp]; - regflags = historyf[temp]; - m68k_dumpstate(NULL); + regs = history[temp]; + regflags = historyf[temp]; + m68k_dumpstate (NULL); #else - m68k_disasm(history[temp], NULL, 1); + m68k_disasm (stdout, history[temp], NULL, 1); #endif - if (++temp == MAX_HIST) temp = 0; - } + if (++temp == MAX_HIST) temp = 0; + } #ifdef NEED_TO_DEBUG_BADLY - regs = save_regs; - regflags = save_flags; + regs = save_regs; + regflags = save_flags; #endif + } + break; + case 'm': + { + uae_u32 maddr; int lines; + if (more_params(&inptr)) + maddr = readhex(&inptr); + else + maddr = nxmem; + if (more_params(&inptr)) + lines = readhex(&inptr); + else + lines = 20; + dumpmem(maddr, &nxmem, lines); + } + break; + case 'o': + { + uae_u32 maddr; + int lines; + + if (more_params(&inptr)) { + maddr = readhex(&inptr); + if (maddr == 1 || maddr == 2) + maddr = get_copper_address (maddr); } + else + maddr = nxcopper; + + if (more_params (&inptr)) + lines = readhex (&inptr); + else + lines = 20; + + nxcopper = decode_copperlist (stdout, maddr, lines); break; - case 'm': - { - uae_u32 maddr; int lines; - if (more_params(&inptr)) - maddr = readhex(&inptr); - else - maddr = nxmem; - if (more_params(&inptr)) - lines = readhex(&inptr); - else - lines = 16; - dumpmem(maddr, &nxmem, lines); + } + case 'O': + if (more_params (&inptr)) { + int plane = readint (&inptr); + int offs = readint (&inptr); + if (plane >= 0 && plane < 8) + bpl_off[plane] = offs; + } else { + int i; + for (i = 0; i < 8; i++) + console_out ("Plane %d offset %d\n", i, bpl_off[i]); } break; - case 'h': - case '?': + case 'h': + case '?': + debug_help (); + break; + } + } +} + +void debug (void) +{ + int i; + + bogusframe = 1; + + if (do_skip && skipaddr_start == 0xC0DEDBAD) { +#if 0 + if (trace_same_insn_count > 0) { + if (memcmp (trace_insn_copy, regs.pc_p, 10) == 0 + && memcmp (trace_prev_regs.regs, regs.regs, sizeof regs.regs) == 0) { - printf (" HELP for UAE Debugger\n"); - printf (" -----------------------\n\n"); - printf (" g:
Start execution at the current address or
\n"); - printf (" c: Dump state of the CIA and custom chips\n"); - printf (" r: Dump state of the CPU\n"); - printf (" m
: Memory dump starting at
\n"); - printf (" d
: Disassembly starting at
\n"); - printf (" t: Step one instruction\n"); - printf (" z: Step through one instruction - useful for JSR, DBRA etc\n"); - printf (" f
: Step forward until PC ==
\n"); - printf (" H : Show PC history instructions\n"); - printf (" M: Search for *Tracker sound modules\n"); - printf (" C : Search for values like energy or lifes in games\n"); - printf (" W
: Write into Amiga memory\n"); - printf (" S : Save a block of Amiga memory\n"); - printf (" h,?: Show this help page\n"); - printf (" q: Quit the emulator. You don't want to use this command.\n\n"); + trace_same_insn_count++; + return; } - break; + } + if (trace_same_insn_count > 1) + fprintf (logfile, "[ repeated %d times ]\n", trace_same_insn_count); +#endif + m68k_dumpstate (logfile, &nextpc); + trace_same_insn_count = 1; + memcpy (trace_insn_copy, regs.pc_p, 10); + memcpy (&trace_prev_regs, ®s, sizeof regs); + } + if (!memwatch_triggered) { + if (do_skip) { + uae_u32 pc = munge24 (m68k_getpc()); + uae_u16 opcode = currprefs.cpu_compatible ? regs.ir : get_word (pc); + int bp = 0; + + for (i = 0; i < BREAKPOINT_TOTAL; i++) { + if (!bpnodes[i].enabled) + continue; + if (bpnodes[i].addr == pc) { + bp = 1; + console_out ("Breakpoint at %08.8X\n", pc); + break; + } + } + if (skipaddr_doskip) { + if (skipaddr_start == pc) + bp = 1; + if (skipins != 0xffffffff) { + if (skipins == 0x10000) { + if (opcode == 0x4e75 || opcode == 0x4e73 || opcode == 0x4e77) + bp = 1; + } else if (opcode == skipins) + bp = 1; + } else if (skipaddr_start == 0xffffffff && skipaddr_doskip < 0) { + if ((pc < 0xe00000 || pc >= 0x1000000) && opcode != 0x4ef9) + bp = 1; + } else if (skipaddr_start == 0xffffffff && skipaddr_doskip > 0) { + bp = 1; + } else if (skipaddr_end != 0xffffffff) { + if (pc >= skipaddr_start && pc < skipaddr_end) + bp = 1; + } + } + if (!bp) { + set_special (SPCFLAG_BRK); + return; + } + } + } else { + write_log ("Memwatch %d: break at %08.8X.%c %c %08.8X\n", memwatch_triggered - 1, mwhit.addr, + mwhit.size == 1 ? 'B' : (mwhit.size == 2 ? 'W' : 'L'), mwhit.rw ? 'W' : 'R', mwhit.val); + memwatch_triggered = 0; + } + if (skipaddr_doskip > 0) { + skipaddr_doskip--; + if (skipaddr_doskip > 0) { + set_special (SPCFLAG_BRK); + return; } } + +#ifdef NEED_TO_DEBUG_BADLY + history[lasthist] = regs; + historyf[lasthist] = regflags; +#else + history[lasthist] = m68k_getpc(); +#endif + if (++lasthist == MAX_HIST) lasthist = 0; + if (lasthist == firsthist) { + if (++firsthist == MAX_HIST) firsthist = 0; + } +#if 0 + inputdevice_unacquire (); + pause_sound (); +#endif + do_skip = 0; + skipaddr_start = 0xffffffff; + skipaddr_end = 0xffffffff; + skipins = 0xffffffff; + skipaddr_doskip = 0; + exception_debugging = 0; + debug_1 (); + for (i = 0; i < BREAKPOINT_TOTAL; i++) { + if (bpnodes[i].enabled) + do_skip = 1; + } + if (do_skip) { + set_special (SPCFLAG_BRK); + debugging = 1; + } +#if 0 + resume_sound (); + inputdevice_acquire (); +#endif +} + +int notinrom (void) +{ + if (munge24 (m68k_getpc()) < 0xe0000) + return 1; + return 0; +} + +const char *debuginfo (int mode) +{ + static char txt[100]; + uae_u32 pc = m68k_getpc(); + sprintf (txt, "PC=%08.8X INS=%04.4X %04.4X %04.4X", + pc, get_word(pc), get_word(pc+2), get_word(pc+4)); + return txt; }