mirror of
https://github.com/kanjitalk755/macemu.git
synced 2024-11-26 10:49:21 +00:00
Merge pull request #129 from rickyzhang82/pr-cxmon-break-point
[Revised] Add break point functions to Basilisk II
This commit is contained in:
commit
e273bb1a0b
@ -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"
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -31,6 +31,12 @@
|
||||
#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 (IS_BREAK_POINT(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 (IS_BREAK_POINT(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
|
||||
|
@ -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");
|
||||
|
@ -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 IS_BREAK_POINT(address) (active_break_points.find(address) != active_break_points.end())
|
||||
|
||||
#endif
|
||||
|
@ -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,256 @@ void binary_dump(void)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
FILE *file;
|
||||
if (!(file = fopen(mon_string, "r"))) {
|
||||
mon_error("Unable to create file");
|
||||
return;
|
||||
}
|
||||
|
||||
char line_buff[1024];
|
||||
bool is_disabled_break_points = 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!");
|
||||
fclose(file);
|
||||
return;
|
||||
}
|
||||
|
||||
while (fgets(line_buff, sizeof(line_buff), file) != NULL) {
|
||||
if (strcmp(line_buff, STR_DISABLED_BREAK_POINTS) == 0) {
|
||||
is_disabled_break_points = true;
|
||||
continue;
|
||||
}
|
||||
uintptr address;
|
||||
std::stringstream ss;
|
||||
ss << std::hex << line_buff;
|
||||
ss >> address;
|
||||
if (is_disabled_break_points)
|
||||
disabled_break_points.insert(address);
|
||||
else
|
||||
active_break_points.insert(address);
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Disassemble
|
||||
* d [start [end]]
|
||||
|
@ -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);
|
||||
|
22
cxmon/utils/README.md
Normal file
22
cxmon/utils/README.md
Normal file
@ -0,0 +1,22 @@
|
||||
# What
|
||||
suspend.bin is a MacBinary file which should be unpacked and run in M68k Macintosh only. It runs emul_op `0x7138` and trigger BasiliskII into cxmon so that you can add break points there.
|
||||
|
||||
# How
|
||||
1. You must build Basilisk II `--with-mon=YES` options.
|
||||
1. Copy suspend.bin into Macintosh guest OS.
|
||||
1. Unpack it with MacBinary.
|
||||
1. Run the program when you want to add break points.
|
||||
1. Once you are in cxmon, type `h` and you can see the new break point commands.
|
||||
1. Once you are done, type `x` to return back to emulation.
|
||||
|
||||
# Break point commands
|
||||
|
||||
```bash
|
||||
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
|
||||
```
|
BIN
cxmon/utils/suspend.bin
Normal file
BIN
cxmon/utils/suspend.bin
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user