Add break point function for Basilisk II in cxmon.

To enter break point, you need to run a m68k program in Macintosh guest OS. The program
executes a new emul_op instruction 0x7138. The program will be provided
in cxmon/utils folder in a separate commit. Once emulation is suspended,
you can enter below new cxmon command to manipluate break points:

ba [address]             Add a break point
br [breakpoints#]        Remove a break point. If # is 0, remove all break points.
bd [breakpoints#]        Disable a break point. If # is 0, disable all break points.
be [breakpoints#]        Enable a break point. If # is 0, enable all break points.
bi                       List all break points
bs "file"                Save all break points to a file
bl "file"                Load break points from a file

Once emulation PC reach break point address, it automatically suspends
and traps into cxmon.

Signed-off-by: Ricky Zhang <rickyzhang@gmail.com>
This commit is contained in:
Ricky Zhang 2017-09-01 10:47:22 -04:00
parent 723bedd55a
commit f3895493ae
8 changed files with 386 additions and 27 deletions

View File

@ -564,6 +564,23 @@ void EmulOp(uint16 opcode, M68kRegisters *r)
r->a[0] = ReadMacInt32(0x2b6);
break;
case M68K_EMUL_OP_SUSPEND: {
printf("*** Suspend\n");
printf("d0 %08x d1 %08x d2 %08x d3 %08x\n"
"d4 %08x d5 %08x d6 %08x d7 %08x\n"
"a0 %08x a1 %08x a2 %08x a3 %08x\n"
"a4 %08x a5 %08x a6 %08x a7 %08x\n"
"sr %04x\n",
r->d[0], r->d[1], r->d[2], r->d[3], r->d[4], r->d[5], r->d[6], r->d[7],
r->a[0], r->a[1], r->a[2], r->a[3], r->a[4], r->a[5], r->a[6], r->a[7],
r->sr);
#ifdef ENABLE_MON
char *arg[4] = {"mon", "-m", "-r", NULL};
mon(3, arg);
#endif
break;
}
default:
printf("FATAL: EMUL_OP called with bogus opcode %08x\n", opcode);
printf("d0 %08x d1 %08x d2 %08x d3 %08x\n"

View File

@ -90,6 +90,7 @@ enum {
M68K_EMUL_OP_SOUNDIN_CLOSE,
M68K_EMUL_OP_DEBUGUTIL,
M68K_EMUL_OP_IDLE_TIME,
M68K_EMUL_OP_SUSPEND,
M68K_EMUL_OP_MAX // highest number
};

View File

@ -43,11 +43,6 @@ extern int intlev(void); // From baisilisk_glue.cpp
B2_mutex *spcflags_lock = NULL;
#endif
#if ENABLE_MON
#include "mon.h"
#include "mon_disass.h"
#endif
bool quit_program = false;
struct flag_struct regflags;

View File

@ -30,7 +30,13 @@
#include "m68k.h"
#include "readcpu.h"
#include "spcflags.h"
#if ENABLE_MON
#include "mon.h"
#include "mon_disass.h"
#endif
extern int areg_byteinc[];
extern int imm8_table[];
@ -74,6 +80,7 @@ struct comptbl {
#endif
extern void REGPARAM2 op_illg (uae_u32) REGPARAM;
extern void m68k_dumpstate(uaecptr *nextpc);
typedef char flagtype;
@ -147,8 +154,6 @@ static __inline__ uae_u32 get_ilong_prefetch (uae_s32 o)
}
#endif
#define m68k_incpc(o) (regs.pc_p += (o))
static __inline__ void fill_prefetch_0 (void)
{
#if USE_PREFETCH_BUFFER
@ -175,6 +180,55 @@ static __inline__ void fill_prefetch_2 (void)
#define fill_prefetch_2 fill_prefetch_0
#endif
static __inline__ uaecptr m68k_getpc (void)
{
#if REAL_ADDRESSING || DIRECT_ADDRESSING
return get_virtual_address(regs.pc_p);
#else
return regs.pc + ((char *)regs.pc_p - (char *)regs.pc_oldp);
#endif
}
static __inline__ void m68k_setpc (uaecptr newpc)
{
#if ENABLE_MON
uae_u32 previous_pc = m68k_getpc();
#endif
#if REAL_ADDRESSING || DIRECT_ADDRESSING
regs.pc_p = get_real_address(newpc);
#else
regs.pc_p = regs.pc_oldp = get_real_address(newpc);
regs.pc = newpc;
#endif
#if ENABLE_MON
if(isBreakPoint(newpc)) {
printf("Stopped at break point address: %08lx. Last PC: %08lx\n", newpc, previous_pc);
m68k_dumpstate(NULL);
char *arg[4] = {"mon", "-m", "-r", NULL};
mon(3, arg);
}
#endif // end of #if ENABLE_MON
}
static __inline__ void m68k_incpc (uae_s32 delta)
{
#if ENABLE_MON
uae_u32 previous_pc = m68k_getpc();
#endif
regs.pc_p += (delta);
#if ENABLE_MON
uaecptr next_pc = m68k_getpc();
if(isBreakPoint(next_pc)) {
printf("Stopped at break point address: %08lx. Last PC: %08lx\n", next_pc, previous_pc);
m68k_dumpstate(NULL);
char *arg[4] = {"mon", "-m", "-r", NULL};
mon(3, arg);
}
#endif // end of #if ENABLE_MON
}
/* These are only used by the 68020/68881 code, and therefore don't
* need to handle prefetch. */
static __inline__ uae_u32 next_ibyte (void)
@ -198,25 +252,6 @@ static __inline__ uae_u32 next_ilong (void)
return r;
}
static __inline__ void m68k_setpc (uaecptr newpc)
{
#if REAL_ADDRESSING || DIRECT_ADDRESSING
regs.pc_p = get_real_address(newpc);
#else
regs.pc_p = regs.pc_oldp = get_real_address(newpc);
regs.pc = newpc;
#endif
}
static __inline__ uaecptr m68k_getpc (void)
{
#if REAL_ADDRESSING || DIRECT_ADDRESSING
return get_virtual_address(regs.pc_p);
#else
return regs.pc + ((char *)regs.pc_p - (char *)regs.pc_oldp);
#endif
}
#define m68k_setpc_fast m68k_setpc
#define m68k_setpc_bcc m68k_setpc
#define m68k_setpc_rte m68k_setpc

View File

@ -55,6 +55,9 @@ extern "C" {
#define VERSION "3"
#endif
// Break points
BREAK_POINT_SET active_break_points;
BREAK_POINT_SET disabled_break_points;
// Buffer we're operating on
bool mon_use_real_mem = false;
@ -1043,6 +1046,13 @@ void mon_init()
mon_add_command("i", ascii_dump, "i [start [end]] ASCII memory dump\n");
mon_add_command("m", memory_dump, "m [start [end]] Hex/ASCII memory dump\n");
mon_add_command("b", binary_dump, "b [start [end]] Binary memory dump\n");
mon_add_command("ba", break_point_add, "ba [address] Add a break point\n");
mon_add_command("br", break_point_remove, "br [breakpoints#] Remove a break point. If # is 0, remove all break points.\n");
mon_add_command("bd", break_point_disable, "bd [breakpoints#] Disable a break point. If # is 0, disable all break points.\n");
mon_add_command("be", break_point_enable, "be [breakpoints#] Enable a break point. If # is 0, enable all break points.\n");
mon_add_command("bi", break_point_info, "bi List all break points\n");
mon_add_command("bs", break_point_save, "bs \"file\" Save all break points to a file\n");
mon_add_command("bl", break_point_load, "bl \"file\" Load break points from a file\n");
mon_add_command("d", disassemble_ppc, "d [start [end]] Disassemble PowerPC code\n");
mon_add_command("d65", disassemble_6502, "d65 [start [end]] Disassemble 6502 code\n");
mon_add_command("d68", disassemble_680x0, "d68 [start [end]] Disassemble 680x0 code\n");

View File

@ -22,6 +22,7 @@
#define MON_H
#include <stdio.h>
#include <set>
/*
@ -80,6 +81,10 @@ extern uint32 mon_mem_size; // Size of mon buffer (if mon_use_real_mem = fals
extern bool mon_macos_mode; // Flag: enable features in the disassembler for working with MacOS code
typedef std::set<uintptr> BREAK_POINT_SET;
extern BREAK_POINT_SET active_break_points;
extern BREAK_POINT_SET disabled_break_points;
// Add command to mon
extern void mon_add_command(const char *name, void (*func)(), const char *help_text);
@ -97,4 +102,7 @@ extern void mon_write_half(uintptr adr, uint32 w);
extern uint32 mon_read_word(uintptr adr);
extern void mon_write_word(uintptr adr, uint32 l);
// Check if break point is set
#define isBreakPoint(address) (active_break_points.find(address) != active_break_points.end())
#endif

View File

@ -22,6 +22,7 @@
#include <stdlib.h>
#include <assert.h>
#include <sstream>
#include "mon.h"
#include "mon_cmd.h"
@ -32,6 +33,9 @@
#endif
static const char* STR_ACTIVE_BREAK_POINTS = "Active Break Points:\n";
static const char* STR_DISABLED_BREAK_POINTS = "Disabled Break Points:\n";
/*
* range_args = [expression] [[COMMA] expression] END
*
@ -302,6 +306,288 @@ void binary_dump(void)
}
/*
* Add Break Point
*/
void break_point_add(void)
{
uintptr address;
if (mon_token == T_END ||
!mon_expression(&address)) {
fprintf(monerr, "Expect break point in hexadecimal.\n");
return;
}
if (mon_token != T_END) {
mon_error("Too many arguments");
return;
}
BREAK_POINT_SET::iterator it;
// Save break point
if((it = disabled_break_points.find(address)) == disabled_break_points.end())
active_break_points.insert(address);
else {
disabled_break_points.erase(it);
active_break_points.insert(address);
}
}
/*
* Remove Break Point
*/
void break_point_remove(void)
{
uintptr index;
if (mon_token == T_END ||
!mon_expression(&index)) {
fprintf(monerr, "Expect index number of break point in hexadecimal.\n");
return;
}
if (mon_token != T_END) {
mon_error("Too many arguments");
return;
}
if (index > active_break_points.size()) {
mon_error("Illegal Index Number!");
return;
}
BREAK_POINT_SET::iterator it;
if (0 == index) {
active_break_points.clear();
printf("Removed all break points!\n");
return;
}
int pos = 1;
for (it = active_break_points.begin(); it != active_break_points.end(); it++)
if (pos++ == index)
break;
// 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 (mon_token == T_END ||
!mon_expression(&index)) {
fprintf(monerr, "Expect index number of break point in hexadecimal.\n");
return;
}
if (mon_token != T_END) {
mon_error("Too many arguments");
return;
}
if (index > active_break_points.size()) {
mon_error("Illegal Index Number!");
return;
}
BREAK_POINT_SET::iterator it;
if (0 == index) {
for (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;
}
int pos = 1;
for (it = active_break_points.begin(); it != active_break_points.end(); it++)
if (pos++ == index)
break;
// 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 (mon_token == T_END ||
!mon_expression(&index)) {
fprintf(monerr, "Expect index number of break point in hexadecimal.\n");
return;
}
if (mon_token != T_END) {
mon_error("Too many arguments");
return;
}
if (index > disabled_break_points.size()) {
mon_error("Illegal Index Number!");
return;
}
BREAK_POINT_SET::iterator it;
if (0 == index) {
for (it = disabled_break_points.begin(); it != disabled_break_points.end(); it++)
active_break_points.insert(*it);
disabled_break_points.clear();
printf("Enabled all break points!\n");
return;
}
int pos = 1;
for (it = disabled_break_points.begin(); it != disabled_break_points.end(); it++)
if (pos++ == index)
break;
// 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;
int pos;
if (!active_break_points.empty()) {
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);
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)
{
FILE *file;
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;
}
if (!(file = fopen(mon_string, "w")))
mon_error("Unable to create file");
else {
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)
{
FILE *file;
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;
}
if (!(file = fopen(mon_string, "r")))
mon_error("Unable to create file");
else{
char line_buff[1024];
bool isDisabledBreakPoints = false;;
if(fgets(line_buff, sizeof(line_buff), file) == NULL ||
strcmp(line_buff, STR_ACTIVE_BREAK_POINTS) != 0) {
mon_error("Invalid break point file format!");
return;
}
while(fgets(line_buff, sizeof(line_buff), file) != NULL) {
if(strcmp(line_buff, STR_DISABLED_BREAK_POINTS) == 0) {
isDisabledBreakPoints = true;
continue;
}
uintptr address;
std::stringstream ss;
ss << std::hex << line_buff;
ss >> address;
if(isDisabledBreakPoints)
disabled_break_points.insert(address);
else
active_break_points.insert(address);
}
fclose(file);
}
}
/*
* Disassemble
* d [start [end]]

View File

@ -28,6 +28,13 @@ extern void shell_command(void);
extern void memory_dump(void);
extern void ascii_dump(void);
extern void binary_dump(void);
extern void break_point_add(void);
extern void break_point_remove(void);
extern void break_point_disable(void);
extern void break_point_enable(void);
extern void break_point_info(void);
extern void break_point_save(void);
extern void break_point_load(void);
extern void disassemble_ppc(void);
extern void disassemble_6502(void);
extern void disassemble_680x0(void);