#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <signal.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include "MacsBug.h"
Gdb_Plugin gdb_printf_command = NULL;
int control_level = 0;
int reading_raw = 0;
static unsigned long *bkpt_tbl = NULL;
static int bkpt_tbl_sz = 0;
static int bkpt_tbl_index = -1;
#define BKPT_DELTA 50
static Gdb_Plugin gdb_set_command = NULL;
static Gdb_Plugin gdb_help_command = NULL;
static Gdb_Plugin gdb_run_command = NULL;
static Gdb_Plugin gdb_shell_command = NULL;
static Gdb_Plugin gdb_make_command = NULL;
static Gdb_Plugin gdb_list_command = NULL;
static Gdb_Plugin gdb_next_command = NULL;
static Gdb_Plugin gdb_step_command = NULL;
static Gdb_Plugin gdb_nexti_command = NULL;
static Gdb_Plugin gdb_stepi_command = NULL;
static Gdb_Plugin gdb_define_command = NULL;
static Gdb_Plugin gdb_document_command = NULL;
static Gdb_Plugin gdb_if_command = NULL;
static Gdb_Plugin gdb_while_command = NULL;
static Gdb_Plugin gdb_file_command = NULL;
static Gdb_Plugin gdb_attach_command = NULL;
static Gdb_Plugin gdb_symbol_file_command=NULL;
static Gdb_Plugin gdb_sharedlibrary_command=NULL;
static Gdb_Plugin gdb_load_command = NULL;
typedef void (*SigHandler)(int);
static SigHandler prev_SIGWINCH_handler = NULL;
static SigHandler prev_SIGCONT_handler = NULL;
static SigHandler prev_SIGINT_handler = NULL;
static SigHandler prev_SIGTSTP_handler = NULL;
static void my_signal_handler(int signo)
{
char prompt[1024];
switch (signo) {
case SIGTSTP:
if (macsbug_screen)
position_cursor_for_shell_input();
if (log_stream)
fclose(log_stream);
signal(SIGTSTP, SIG_DFL);
sigsetmask(0);
kill(getpid(), SIGTSTP);
signal(SIGTSTP, my_signal_handler);
break;
case SIGCONT:
if (prev_SIGCONT_handler)
prev_SIGCONT_handler(signo);
signal(SIGCONT, my_signal_handler);
if (macsbug_screen)
refresh(NULL, 0);
#if 0
if (log_stream) {
log_stream = fopen(log_filename, "a");
if (!log_stream)
gdb_fprintf(gdb_current_stderr, "Cannot reopen log file: %s", strerror(errno));
}
#endif
fprintf(stderr, "%s", gdb_get_prompt(prompt));
break;
case SIGWINCH:
if (prev_SIGWINCH_handler)
prev_SIGWINCH_handler(signo);
signal(SIGWINCH, my_signal_handler);
__window_size(NULL, 0);
get_screen_size(&max_rows, &max_cols);
save_stack(max_rows);
if (macsbug_screen) {
if (max_rows < MIN_SCREEN_ROWS || max_cols < MIN_SCREEN_COLS) {
macsbug_off(0);
gdb_error(COLOR_RED "Terminal window too small (must be at least %ld rows and %ld columns)." COLOR_OFF "\n",
MIN_SCREEN_ROWS, MIN_SCREEN_COLS);
return;
}
refresh(NULL, 0);
fprintf(stderr, "%s", gdb_get_prompt(prompt));
}
break;
case SIGINT:
printf("My SIGINT\n");
control_level = reading_raw = 0;
if (prev_SIGINT_handler)
prev_SIGINT_handler(signo);
signal(SIGINT, my_signal_handler);
break;
default:
gdb_internal_error("Unexpected signal detected in MacsBug signal handler");
break;
}
}
void run_command(char *arg, int from_tty)
{
gdb_run_command(arg, from_tty);
__window_size(NULL, 0);
gdb_set_int("$dot", 0);
gdb_set_int("$__running__", 1);
gdb_set_int("$__lastcmd__", -1);
gdb_set_int("$__next_addr__", -1);
gdb_set_int("$__prev_dm_n__", 0);
gdb_set_int("$__prev_dma_n__", 0);
gdb_set_int("$macsbug_screen", macsbug_screen);
need_CurApName = 1;
init_sidebar_and_pc_areas();
}
static void set_command(char *arg, int from_tty)
{
gdb_set_command(arg, from_tty);
Update_PC_and_SideBare_Areas();
}
static void help_command(char *arg, int from_tty)
{
gdb_help_command(arg, from_tty);
if (!arg)
gdb_printf("\nType \"help mb-notes\" or just \"mb-notes\" to get additional info about MacsBug.\n");
}
static void shell_command(char *arg, int from_tty)
{
GDB_FILE *curr_stdout, *curr_stderr;
if (!gdb_shell_command)
return;
if (macsbug_screen) {
position_cursor_for_shell_input();
curr_stdout = gdb_current_stdout;
gdb_redirect_output(gdb_default_stdout);
curr_stderr = gdb_current_stderr;
gdb_redirect_output(gdb_default_stderr);
}
gdb_shell_command(arg, from_tty);
if (macsbug_screen) {
if (gdb_query(COLOR_RED "Refresh MacsBug screen now? ")) {
fprintf(stderr, COLOR_OFF);
gdb_redirect_output(curr_stdout);
gdb_redirect_output(curr_stderr);
refresh(NULL, 0);
} else {
fprintf(stderr, COLOR_OFF);
macsbug_off(0);
}
}
}
static void make_command(char *arg, int from_tty)
{
GDB_FILE *curr_stdout, *curr_stderr;
if (!gdb_shell_command)
return;
if (macsbug_screen) {
position_cursor_for_shell_input();
curr_stdout = gdb_current_stdout;
gdb_redirect_output(gdb_default_stdout);
curr_stderr = gdb_current_stderr;
gdb_redirect_output(gdb_default_stderr);
}
gdb_make_command(arg, from_tty);
if (macsbug_screen) {
if (gdb_query(COLOR_RED "Refresh MacsBug screen now? ")) {
fprintf(stderr, COLOR_OFF);
gdb_redirect_output(curr_stdout);
gdb_redirect_output(curr_stderr);
refresh(NULL, 0);
} else {
fprintf(stderr, COLOR_OFF);
macsbug_off(0);
}
}
}
static char *listing_filter(FILE *f, char *line, void *data)
{
if (line)
gdb_fprintf(*(GDB_FILE **)data, CLEAR_LINE "%s", line);
return (NULL);
}
static void enhanced_gdb_listing_cmd(char *arg, int from_tty, int cmdNbr,
void (*cmd)(char*, int))
{
if (from_tty && !macsbug_screen && isatty(STDOUT_FILENO) &&
gdb_get_int("$__lastcmd__") == cmdNbr)
gdb_printf(CURSOR_UP, 2);
if (macsbug_screen)
cmd(arg, from_tty);
else {
GDB_FILE *redirect_stdout, *prev_stdout;
redirect_stdout = gdb_open_output(stdout, listing_filter, &prev_stdout);
prev_stdout = gdb_redirect_output(redirect_stdout);
cmd(arg, from_tty);
gdb_close_output(redirect_stdout);
}
gdb_set_int("$__lastcmd__", cmdNbr);
}
#define ENHANCE_GDB_LISTING_CMD(cmd, cmdNbr) \
static void cmd ## _command(char *arg, int from_tty) \
{ \
enhanced_gdb_listing_cmd(arg, from_tty, cmdNbr, gdb_ ## cmd ## _command); \
}
ENHANCE_GDB_LISTING_CMD(list, 44)
ENHANCE_GDB_LISTING_CMD(next, 45)
ENHANCE_GDB_LISTING_CMD(step, 46)
ENHANCE_GDB_LISTING_CMD(nexti,47)
ENHANCE_GDB_LISTING_CMD(stepi,48)
#define CAUSES_PROGRESS_CMD_PLUGIN(cmd) \
static void cmd ## _command(char *arg, int from_tty) \
{ \
immediate_flush = PROGRESS_REFRESH; \
gdb_ ## cmd ## _command(arg, from_tty); \
immediate_flush = NORMAL_REFRESH; \
}
CAUSES_PROGRESS_CMD_PLUGIN(file)
CAUSES_PROGRESS_CMD_PLUGIN(attach)
CAUSES_PROGRESS_CMD_PLUGIN(symbol_file)
CAUSES_PROGRESS_CMD_PLUGIN(load)
#define CONTROL_CMD_PLUGIN(cmd) \
static void cmd ## _command(char *arg, int from_tty) \
{ \
if (arg && from_tty && macsbug_screen) { \
gdb_printf(#cmd " %s\n", arg); \
gdb_fflush(gdb_current_stdout); \
gdb_define_raw_input_handler(my_raw_input_handler); \
gdb_control_prompt_position(my_prompt_position_function); \
} \
\
control_level = reading_raw = 1; \
\
gdb_ ## cmd ## _command(arg, from_tty); \
}
CONTROL_CMD_PLUGIN(define)
CONTROL_CMD_PLUGIN(document)
CONTROL_CMD_PLUGIN(if)
CONTROL_CMD_PLUGIN(while)
#if 0
static void show_the_command(char *cmd, char *arg, int from_tty)
{
if (arg && from_tty && macsbug_screen) {
gdb_printf("%s %s\n", cmd, arg);
gdb_fflush(gdb_current_stdout);
gdb_define_raw_input_handler(my_raw_input_handler);
gdb_control_prompt_position(my_prompt_position_function);
}
control_level = reading_raw = 1;
}
static void if_command(char *arg, int from_tty)
{
show_the_command("if", arg, from_tty);
gdb_if_command(arg, from_tty);
}
#endif
static void exit_handler(void)
{
if (log_stream) {
gdb_printf("Closing log\n");
fclose(log_stream);
log_stream = NULL;
}
position_cursor_for_shell_input();
}
#if 0
static void quit_command1(char *arg, int from_tty)
{
if (macsbug_screen) {
if (!gdb_target_running())
fprintf(stderr, "\n");
fprintf(stderr, "\n" ERASE_BELOW "\n");
}
quit_command(arg, from_tty);
}
#endif
static int bsearch_compar_bkpt(const void *a1, const void *a2)
{
if (*(unsigned long *)a1 < *(unsigned long *)a2)
return (-1);
if (*(unsigned long *)a1 > *(unsigned long *)a2)
return (1);
return (0);
}
int find_breakpoint(unsigned long address)
{
int i = -1;
unsigned long *p;
if (bkpt_tbl_index >= 0) {
p = bsearch((void *)&address, bkpt_tbl, bkpt_tbl_index+1, sizeof(unsigned long),
bsearch_compar_bkpt);
if (p)
i = p - bkpt_tbl;
}
return (i);
}
static void fix_pc_area_if_necessary(unsigned long address)
{
unsigned long pc;
if (macsbug_screen && gdb_target_running()) {
pc = gdb_get_int("$pc");
if (address >= pc && address < address + (4*pc_area_lines))
force_pc_area_update();
}
}
static int qsort_compar_bkpt(const void *a1, const void *a2)
{
if (*(unsigned long *)a1 < *(unsigned long *)a2)
return (-1);
if (*(unsigned long *)a1 > *(unsigned long *)a2)
return (1);
return (0);
}
static void new_breakpoint(unsigned long address, int enabled)
{
int i;
if (!enabled)
return;
i = find_breakpoint(address);
if (i >= 0)
return;
if (++bkpt_tbl_index >= bkpt_tbl_sz) {
bkpt_tbl_sz += BKPT_DELTA;
bkpt_tbl = gdb_realloc(bkpt_tbl, bkpt_tbl_sz * sizeof(unsigned long));
}
bkpt_tbl[bkpt_tbl_index] = address;
qsort(bkpt_tbl, bkpt_tbl_index+1,
sizeof(unsigned long), qsort_compar_bkpt);
fix_pc_area_if_necessary(address);
if (0)
for (i = 0; i <= bkpt_tbl_index; ++i)
gdb_printf("after add: %2d. 0x%.8lX\n", i+1, bkpt_tbl[i]);
}
static void delete_breakpoint(unsigned long address, int enabled)
{
int i, j;
i = find_breakpoint(address);
if (i >= 0) {
j = i++;
while (i <= bkpt_tbl_index)
bkpt_tbl[j++] = bkpt_tbl[i++];
--bkpt_tbl_index;
}
fix_pc_area_if_necessary(address);
if (0)
for (i = 0; i <= bkpt_tbl_index; ++i)
gdb_printf("after delete: %2d. 0x%.8lX\n", i+1, bkpt_tbl[i]);
}
static void changed_breakpoint(unsigned long address, int enabled)
{
int i;
i = find_breakpoint(address);
if (i < 0) {
if (enabled)
new_breakpoint(address, 1);
return;
}
if (!enabled)
delete_breakpoint(address, 0);
if (0)
for (i = 0; i <= bkpt_tbl_index; ++i)
gdb_printf("after change: %2d. 0x%.8lX\n", i+1, bkpt_tbl[i]);
}
static void registers_changed(void)
{
__display_side_bar(NULL, 0);
}
void state_changed(GdbState newState)
{
switch (newState) {
case Gdb_Not_Active:
fprintf(stderr, "еее state not active\n");
break;
case Gdb_Active:
fprintf(stderr, "еее state active\n");
break;
case Gdb_Target_Loaded:
fprintf(stderr, "еее state target loaded\n");
break;
case Gdb_Target_Exited:
fprintf(stderr, "еее state target exited\n");
break;
case Gdb_Target_Running:
fprintf(stderr, "еее state target running\n");
break;
case Gdb_Target_Stopped:
fprintf(stderr, "еее state target stopped\n");
break;
}
}
void init_macsbug_patches(void)
{
static int firsttime = 1;
if (firsttime) {
firsttime = 0;
gdb_run_command = gdb_replace_command("run", run_command);
if (!gdb_run_command)
gdb_internal_error("internal error - run command not found");
#if 0
gdb_set_command = gdb_replace_command("set", set_command);
if (!gdb_set_command)
gdb_internal_error("internal error - set command not found");
#endif
#if 1
gdb_help_command = gdb_replace_command("help", help_command);
if (!gdb_help_command)
gdb_internal_error("internal error - help command not found");
#endif
gdb_shell_command = gdb_replace_command("shell", shell_command);
if (!gdb_shell_command)
gdb_internal_error("internal error - shell command not found");
gdb_make_command = gdb_replace_command("make", make_command);
if (!gdb_make_command)
gdb_internal_error("internal error - make command not found");
gdb_list_command = gdb_replace_command("list", list_command);
if (!gdb_list_command)
gdb_internal_error("internal error - list command not found");
gdb_next_command = gdb_replace_command("next", next_command);
if (!gdb_next_command)
gdb_internal_error("internal error - next command not found");
gdb_step_command = gdb_replace_command("step", step_command);
if (!gdb_step_command)
gdb_internal_error("internal error - step command not found");
gdb_nexti_command = gdb_replace_command("nexti", nexti_command);
if (!gdb_nexti_command)
gdb_internal_error("internal error - nexti command not found");
gdb_stepi_command = gdb_replace_command("stepi", stepi_command);
if (!gdb_stepi_command)
gdb_internal_error("internal error - stepi command not found");
gdb_define_command = gdb_replace_command("define", define_command);
if (!gdb_shell_command)
gdb_internal_error("internal error - define command not found");
gdb_document_command = gdb_replace_command("document", document_command);
if (!gdb_document_command)
gdb_internal_error("internal error - document command not found");
gdb_if_command = gdb_replace_command("if", if_command);
if (!gdb_if_command)
gdb_internal_error("internal error - if command not found");
gdb_while_command = gdb_replace_command("while", while_command);
if (!gdb_while_command)
gdb_internal_error("internal error - while command not found");
gdb_printf_command = gdb_replace_command("printf", NULL);
if (!gdb_printf_command)
gdb_internal_error("internal error - printf command not found");
gdb_file_command = gdb_replace_command("file", file_command);
if (!gdb_file_command)
gdb_internal_error("internal error - file command not found");
gdb_attach_command = gdb_replace_command("attach", attach_command);
if (!gdb_attach_command)
gdb_internal_error("internal error - attach command not found");
gdb_symbol_file_command = gdb_replace_command("symbol-file", symbol_file_command);
if (!gdb_symbol_file_command)
gdb_internal_error("internal error - symbol-file command not found");
#if 0
gdb_sharedlibrary_command = gdb_replace_command("sharedlibrary", sharedlibrary_command);
if (!gdb_sharedlibrary_command)
gdb_internal_error("internal error - sharedlibrary command not found");
#endif
gdb_load_command = gdb_replace_command("load", load_command);
if (!gdb_load_command)
gdb_internal_error("internal error - load command not found");
#if 0
quit_command = gdb_replace_command("quit", quit_command1);
if (!quit_command)
gdb_internal_error("internal error - quit command not found");
#else
gdb_define_exit_handler(exit_handler);
#endif
prev_SIGCONT_handler = signal(SIGCONT, my_signal_handler);
prev_SIGWINCH_handler = signal(SIGWINCH, my_signal_handler);
gdb_special_events(Gdb_After_Creating_Breakpoint, (Gdb_Callback)new_breakpoint);
gdb_special_events(Gdb_Before_Deleting_Breakpoint, (Gdb_Callback)delete_breakpoint);
gdb_special_events(Gdb_After_Modified_Breakpoint, (Gdb_Callback)changed_breakpoint);
}
}