#include <fcntl.h>
#include <mach/mach.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/param.h>
#include <sys/ptrace.h>
#include <sys/termios.h>
#include <unistd.h>
#include "macosx-low.h"
#include "macosx-mutils.h"
#include "gdb/signals.h"
static unsigned char macosx_translate_exception (struct macosx_exception_thread_message *msg);
int low_debuglevel = 0;
extern unsigned long signal_pid;
static int last_sent_signal = 0;
static int gdbserver_has_a_terminal (void);
static void terminal_inferior (void);
static void terminal_ours (void);
static int terminal_is_ours = 0;
static int attached_to_process = 0;
static int inferior_ttystate_err = -1;
static struct termios inferior_ttystate;
static pid_t inferior_process_group = -1;
static int inferior_tflags;
static int our_ttystate_err = -1;
static struct termios our_ttystate;
static pid_t our_process_group = -1;
static int our_tflags;
static void
macosx_low_debug (int level, const char *fmt, ...)
{
va_list ap;
if (low_debuglevel >= level)
{
va_start (ap, fmt);
printf ("[%d/%d macosx-low]: ", getpid (), mach_thread_self ());
vprintf (fmt, ap);
va_end (ap);
fflush (stdout);
}
}
void
mach_check_error (kern_return_t ret, const char *file,
unsigned int line, const char *func)
{
if (ret == KERN_SUCCESS)
{
return;
}
if (func == NULL)
{
func = "[UNKNOWN]";
}
error ("error on line %u of \"%s\" in function \"%s\": %s (0x%lx)\n",
line, file, func, MACH_ERROR_STRING (ret), (unsigned long) ret);
}
void
mach_warn_error (kern_return_t ret, const char *file,
unsigned int line, const char *func)
{
if (ret == KERN_SUCCESS)
{
return;
}
if (func == NULL)
{
func = "[UNKNOWN]";
}
warning ("error on line %u of \"%s\" in function \"%s\": %s (0x%ux)",
line, file, func, MACH_ERROR_STRING (ret), ret);
}
static struct macosx_process_info *create_process (pid_t pid);
struct macosx_process_info current_macosx_process;
static struct macosx_process_info *
create_process (int pid)
{
struct macosx_process_info *process;
kern_return_t kret;
process = ¤t_macosx_process;
memset (process, 0, sizeof (struct macosx_process_info));
process->pid = pid;
process->status = (macosx_exception_thread_status *)
malloc (sizeof (macosx_exception_thread_status));
macosx_exception_thread_init (process->status);
kret = task_for_pid (mach_task_self (), pid, &(process->status->task));
if (kret != KERN_SUCCESS)
{
error ("Unable to find Mach task port for process-id %d: %s (0x%lx).",
pid, MACH_ERROR_STRING (kret), (unsigned long) kret);
}
macosx_exception_thread_create (process->status);
return process;
}
struct mach_thread_list
{
thread_array_t thread_list;
unsigned int nthreads;
};
void
check_native_thread_exists (struct inferior_list_entry *entry, void *data)
{
struct mach_thread_list *threads = (struct mach_thread_list *) data;
int i;
int found_it = 0;
for (i = 0; i < threads->nthreads; i++)
{
if (entry->id == threads->thread_list[i])
{
found_it = 1;
break;
}
}
if (!found_it)
{
remove_thread ((struct thread_info *) entry);
}
}
void
macosx_check_new_threads (struct macosx_process_info *process)
{
thread_array_t thread_list = NULL;
unsigned int nthreads = 0;
kern_return_t kret;
int i;
struct mach_thread_list threads;
kret = task_threads (process->status->task, &thread_list, &nthreads);
MACH_CHECK_ERROR (kret);
threads.nthreads = nthreads;
threads.thread_list = thread_list;
for_each_inferior_data (&all_threads, &threads, check_native_thread_exists);
for (i = 0; i < nthreads; i++)
{
if (find_inferior_id (&all_threads, thread_list[i]) == NULL)
{
struct macosx_thread_info *new_thread =
(struct macosx_thread_info *) malloc (sizeof (struct macosx_thread_info));
new_thread->process = process;
add_thread (thread_list[i], new_thread, thread_list[i]);
}
}
kret = vm_deallocate (mach_task_self (), (vm_address_t) thread_list,
(vm_size_t) (nthreads * sizeof (thread_t)));
MACH_CHECK_ERROR (kret);
}
static int
wait_for_stop (pid_t pid)
{
int status;
pid_t wait_return;
wait_return = waitpid (pid, &status, WUNTRACED);
if (wait_return == -1)
{
perror ("Error waiting for child to start up");
return -1;
}
return wait_return;
}
static int
macosx_create_inferior (char *program, char **allargs)
{
struct macosx_process_info *new_process;
pid_t pid;
attached_to_process = 0;
gdbserver_has_a_terminal ();
pid = fork ();
if (pid < 0)
perror_with_name ("fork");
if (pid == 0)
{
ptrace (PT_TRACE_ME, 0, 0, 0);
ptrace (PT_SIGEXC, 0, 0, 0);
setpgid (0, 0);
sleep (1);
execv (program, allargs);
error ("Cannot exec %s: %s.\n", program,
strerror (errno));
}
setpgid (pid, pid);
new_process = create_process (pid);
macosx_check_new_threads (new_process);
return pid;
}
static int
macosx_attach (unsigned long pid)
{
struct macosx_process_info *new_process;
gdbserver_has_a_terminal ();
if (ptrace (PT_ATTACHEXC, pid, 0, 0) != 0)
{
fprintf (stderr, "Cannot attach to process %d: %s (%d)\n", pid,
strerror (errno), errno);
fflush (stderr);
return -1;
}
attached_to_process = 1;
new_process = create_process (pid);
macosx_check_new_threads (new_process);
return 0;
}
static void
macosx_kill (void)
{
ptrace (PT_KILL, signal_pid, 0, 0);
}
static void
macosx_detach (void)
{
ptrace (PT_DETACH, signal_pid, 0, 0);
}
static int
macosx_thread_alive (unsigned long tid)
{
int alive = 0;
if (current_macosx_process.status)
alive = macosx_thread_valid ( current_macosx_process.status->task, tid );
macosx_low_debug (6, "macosx_thread_alive (T%8.8x) returning %d (all_threads = %d)\n", tid, alive, find_inferior_id (&all_threads, tid) != NULL);
return alive;
}
struct thread_resume *resume_ptr;
static void
macosx_process_resume_requests (struct inferior_list_entry *entry)
{
struct thread_info *thread = (struct thread_info *) entry;
struct macosx_process_info *process;
struct macosx_thread_info *macosx_thread
= inferior_target_data (thread);
int index = 0;
int ret;
process = get_thread_process (thread);
regcache_invalidate_one (entry);
if (process->status->stopped_in_softexc && process->stopped_thread == entry->id)
{
int sig;
if (resume_ptr[0].thread == -1)
sig = resume_ptr[0].sig;
else
{
while (resume_ptr[index].thread != -1
&& resume_ptr[index].thread != entry->id)
index++;
if (resume_ptr[index].thread == -1)
sig = 0;
else
sig = resume_ptr[index].sig;
}
macosx_low_debug (6, "Updating 0x%x with signal %d\n", entry->id, sig);
ret = ptrace (PT_THUPDATE, process->pid, (caddr_t) entry->id,
sig);
if (ret != 0)
perror ("Error calling PT_THUPDATE");
}
if (process->stepping)
{
if (process->thread_to_step != entry->id)
{
macosx_low_debug (6, "Suspending thread 0x%x\n", entry->id);
thread_suspend (entry->id);
macosx_thread->suspend_count++;
}
else
{
macosx_low_debug (6, "Single stepping thread 0x%x\n", entry->id);
the_low_target.low_single_step_thread (entry->id, 1);
while (macosx_thread->suspend_count > 0)
{
thread_resume (entry->id);
macosx_thread->suspend_count--;
}
}
}
else
{
while (macosx_thread->suspend_count > 0)
{
thread_resume (entry->id);
macosx_thread->suspend_count--;
}
the_low_target.low_single_step_thread (entry->id, 0);
}
}
void
macosx_resume (struct thread_resume *resume_info)
{
struct macosx_process_info *process;
unsigned char charbuf[1] = { 0 };
int index;
resume_ptr = resume_info;
process = get_thread_process (current_inferior);
index = 0;
process->stepping = 0;
while (resume_info[index].thread != -1)
{
macosx_low_debug (6, "macosx_resume resume_info[%d] T%8.8x leave_stopped=%d, step=%d, signal=%d\n", index, resume_info[index].thread, resume_info[index].leave_stopped, resume_info[index].step, resume_info[index].sig);
if (resume_info[index].step == 1)
{
if (process->stepping == 1)
{
warning ("Can only step one thread at a time. "
"Currently stepping %d, asked to step %d\n",
process->thread_to_step,
resume_info[index].thread);
}
else
{
process->stepping = 1;
process->thread_to_step = resume_info[index].thread;
}
}
index++;
}
macosx_low_debug (6, "macosx_resume resume_info[%d] T%8.8x leave_stopped=%d, step=%d, signal=%d\n", index, resume_info[index].thread, resume_info[index].step, resume_info[index].sig);
terminal_inferior ();
block_async_io ();
enable_async_io ();
for_each_inferior (&all_threads, macosx_process_resume_requests);
write (process->status->transmit_to_fd, charbuf, 1);
process->status->stopped_in_softexc = 0;
macosx_low_debug (6, "Called macosx_resume\n");
}
static void
macosx_add_to_port_set (struct macosx_exception_thread_status *excthread,
fd_set * fds)
{
FD_ZERO (fds);
if (excthread->receive_from_fd > 0)
{
FD_SET (excthread->receive_from_fd, fds);
}
if (excthread->error_receive_fd > 0)
{
FD_SET (excthread->error_receive_fd, fds);
}
}
static unsigned char
macosx_translate_exception (struct macosx_exception_thread_message *msg)
{
switch (msg->exception_type)
{
case EXC_BAD_ACCESS:
return TARGET_SIGNAL_BUS;
break;
case EXC_BAD_INSTRUCTION:
return TARGET_SIGNAL_ILL;
break;
case EXC_ARITHMETIC:
return TARGET_EXC_ARITHMETIC;
break;
case EXC_EMULATION:
return TARGET_EXC_EMULATION;
break;
case EXC_SOFTWARE:
{
switch (msg->exception_data[0])
{
case EXC_SOFT_SIGNAL:
return (unsigned char) msg->exception_data[1];
break;
default:
return TARGET_EXC_SOFTWARE;
break;
}
}
break;
case EXC_BREAKPOINT:
return TARGET_SIGNAL_TRAP;
break;
default:
return TARGET_SIGNAL_UNKNOWN;
break;
}
}
enum macosx_event_source
{
MACOSX_SOURCE_NONE,
MACOSX_SOURCE_ERROR,
MACOSX_SOURCE_EXCEPTION,
MACOSX_SOURCE_EXITED,
MACOSX_SOURCE_STOPPED,
MACOSX_SOURCE_SIGNALED
};
enum macosx_event_type
{
MACOSX_TYPE_UNKNOWN,
MACOSX_TYPE_EXCEPTION,
MACOSX_TYPE_SIGNAL,
MACOSX_TYPE_BREAKPOINT,
MACOSX_TYPE_SINGLESTEP
};
struct macosx_event
{
enum macosx_event_source source;
enum macosx_event_type type;
char *data;
struct macosx_event *next;
struct macosx_event *prev;
};
static struct macosx_event *macosx_add_to_events (struct macosx_process_info *inferior,
enum macosx_event_source source,
char *data);
static void macosx_clear_events ();
static struct macosx_event *macosx_event_chain, *macosx_event_tail;
static enum macosx_event_type
macosx_exception_event_type (struct macosx_process_info *inferior,
macosx_exception_thread_message *mssg)
{
if (inferior->stepping
&& (mssg->exception_type == EXC_BREAKPOINT)
&& (inferior->thread_to_step == mssg->thread_port))
return MACOSX_TYPE_SINGLESTEP;
if (mssg->exception_type == EXC_BREAKPOINT)
return MACOSX_TYPE_BREAKPOINT;
if (mssg->exception_type == EXC_SOFTWARE
&& mssg->data_count == 2
&& mssg->exception_data[0] == EXC_SOFT_SIGNAL)
return MACOSX_TYPE_SIGNAL;
return MACOSX_TYPE_EXCEPTION;
}
static struct macosx_event *
macosx_add_to_events (struct macosx_process_info *inferior,
enum macosx_event_source source,
char *data)
{
struct macosx_event *new_event;
new_event = (struct macosx_event *)
malloc (sizeof (struct macosx_event));
new_event->type = MACOSX_TYPE_UNKNOWN;
new_event->source = source;
if (source == MACOSX_SOURCE_EXCEPTION)
{
macosx_exception_thread_message *mssg;
mssg = (macosx_exception_thread_message *)
malloc (sizeof (macosx_exception_thread_message));
memcpy (mssg, data, sizeof (macosx_exception_thread_message));
macosx_low_debug (6, "macosx_add_to_events: adding an exception event "
"to the pending events.\n");
new_event->data = (void *) mssg;
new_event->type = macosx_exception_event_type (inferior, mssg);
}
else if (source == MACOSX_SOURCE_STOPPED)
{
macosx_low_debug (6, "macosx_add_to_events: Adding a stopped event.\n");
new_event->data = data;
new_event->type = MACOSX_TYPE_SIGNAL;
}
else
{
error ("Unrecognized event type in macosx_add_to_events.\n");
}
if (macosx_event_chain == NULL)
{
macosx_event_chain = new_event;
macosx_event_tail = new_event;
new_event->prev = NULL;
new_event->next = NULL;
}
else
{
new_event->prev = macosx_event_tail;
new_event->next = NULL;
macosx_event_tail->next = new_event;
macosx_event_tail = new_event;
}
return new_event;
}
static unsigned char
macosx_service_event (struct macosx_process_info *inferior,
struct macosx_event *event)
{
macosx_exception_thread_message *mssg =
(macosx_exception_thread_message *) event->data;
struct inferior_list_entry *this_inferior;
this_inferior = find_inferior_id (&all_threads, mssg->thread_port);
if (this_inferior == NULL)
{
warning ("The inferior for this thread has gone away");
abort ();
}
current_inferior = (struct thread_info *) this_inferior;
if (inferior->stepping)
{
the_low_target.low_clear_single_step (mssg->thread_port);
inferior->stepping = 0;
}
if (event->source == MACOSX_SOURCE_EXCEPTION)
{
inferior->stopped_thread = mssg->thread_port;
if (event->type == MACOSX_TYPE_SIGNAL)
inferior->status->stopped_in_softexc = 1;
return macosx_translate_exception (mssg);
}
else if (event->source == MACOSX_SOURCE_STOPPED)
{
return (int) event->data;
}
else
error ("Message of unknown source: %d passed to macosx_service_event.\n",
event->source);
return (unsigned char) 0;
}
static void
macosx_free_event (struct macosx_event *event_ptr)
{
if (event_ptr->source == MACOSX_SOURCE_EXCEPTION)
free (event_ptr->data);
free (event_ptr);
}
static void
macosx_clear_events ()
{
struct macosx_event *event_ptr = macosx_event_chain;
while (event_ptr != NULL)
{
macosx_event_chain = event_ptr->next;
macosx_free_event (event_ptr);
event_ptr = macosx_event_chain;
}
}
void
macosx_backup_threads_before_break (struct macosx_event *event_ptr)
{
return;
}
static int got_sigchld;
static void
sigchld_handler (int signo)
{
macosx_low_debug (6, "Called sigchld_handler (%d)\n", signo);
got_sigchld = 1;
}
static int
check_for_sigchld ()
{
int retval = got_sigchld;
got_sigchld = 0;
return retval;
}
enum macosx_event_source
macosx_fetch_event (struct macosx_process_info *inferior,
int timeout,
char *buf,
int *retval)
{
fd_set fds;
int fd, ret;
struct timeval tv;
struct timeval *tv_ptr;
int bypass_select = 0;
int select_errno = 0;
unsigned char check_for_exc_signal = 0;
static macosx_exception_thread_message saved_msg = {0};
*retval = 0;
macosx_low_debug (6, "macosx_fetch_event called with timeout %d.\n", timeout);
if (saved_msg.task_port != MACH_PORT_NULL)
{
macosx_low_debug (6, "Getting mach exception event from cache.\n");
memcpy (buf, &saved_msg, sizeof (saved_msg));
saved_msg.task_port = MACH_PORT_NULL;
*retval = 0;
return MACOSX_SOURCE_EXCEPTION;
}
if (timeout == -1)
tv_ptr = NULL;
else
{
tv.tv_sec = 0;
tv.tv_usec = timeout;
tv_ptr = &tv;
}
for (;;)
{
macosx_add_to_port_set (inferior->status, &fds);
select_errno = 0;
if (check_for_sigchld ())
{
macosx_low_debug (6, "sigchild handler got a hit before"
" entering select\n");
bypass_select = 1;
}
else
{
ret = select (FD_SETSIZE, &fds, NULL, NULL, tv_ptr);
if (ret < 0)
select_errno = errno;
}
macosx_low_debug (6, "Woke up from select: bypass: %d ret: %d errno %d.\n",
bypass_select, ret, select_errno);
if (bypass_select || select_errno == EINTR)
{
pid_t retpid;
int wstatus;
retpid = waitpid (-1, &wstatus, WNOHANG | WUNTRACED );
if (retpid == 0)
continue;
if (retpid != inferior->pid)
{
macosx_low_debug (6, "Interrupted for signal for pid %d\n", retpid);
continue;
}
if (WIFEXITED (wstatus))
{
macosx_low_debug (6, "Process %d exited with status %d\n",
retpid, WEXITSTATUS (wstatus));
*retval = WEXITSTATUS (wstatus);
return MACOSX_SOURCE_EXITED;
}
else if (WIFSIGNALED (wstatus))
{
macosx_low_debug (6, "Process %d terminated with signal %d\n",
retpid, WTERMSIG (wstatus));
*retval = WTERMSIG (wstatus);
return MACOSX_SOURCE_SIGNALED;
}
else if (WIFSTOPPED (wstatus))
{
macosx_low_debug (6, "Process %d stopped with signal %d\n",
retpid, WSTOPSIG (wstatus));
*retval = WSTOPSIG (wstatus);
if (*retval == last_sent_signal && !bypass_select
&& select_errno == EINTR)
{
macosx_low_debug (6, "select () was interrupted with signal "
"%d, check for a matching mach exception "
"message.\n", *retval);
check_for_exc_signal = last_sent_signal;
}
else
return MACOSX_SOURCE_STOPPED;
}
continue;
}
if (ret < 0)
{
error ("unable to select: %s", strerror (select_errno));
}
if (ret == 0)
{
return MACOSX_SOURCE_NONE;
}
break;
}
fd = inferior->status->error_receive_fd;
if (fd > 0 && FD_ISSET (fd, &fds))
{
macosx_low_debug (6, "Reading event from error fd.\n");
read (fd, buf, 1);
return MACOSX_SOURCE_ERROR;
}
fd = inferior->status->receive_from_fd;
if (fd > 0 && FD_ISSET (fd, &fds))
{
macosx_low_debug (6, "Reading event from exception thread.\n");
read (fd, buf, sizeof (macosx_exception_thread_message));
if (check_for_exc_signal != 0)
{
macosx_exception_thread_message *msg = (macosx_exception_thread_message *)buf;
if (macosx_exception_event_type (inferior, msg) == MACOSX_TYPE_SIGNAL)
{
if (((unsigned char) msg->exception_data[1]) == check_for_exc_signal)
{
macosx_low_debug (6, "Matching mach exception event received "
"for signal %d.\n", check_for_exc_signal);
last_sent_signal = 0;
*retval = 0;
}
else
{
macosx_low_debug (6, "Exception thread event signal (%d) doesn't "
"match the reason select was interrupted "
"(%d).\n",
(unsigned char) msg->exception_data[1], *retval);
memcpy(&saved_msg, msg, sizeof(saved_msg));
return MACOSX_SOURCE_STOPPED;
}
}
}
return MACOSX_SOURCE_EXCEPTION;
}
return MACOSX_SOURCE_ERROR;
}
static unsigned char
macosx_wait_for_event (struct thread_info *child,
char *status,
unsigned int timeout)
{
struct macosx_process_info *inferior;
enum macosx_event_source type;
char buf[1024];
int val;
int event_count, keep_looking;
int first_time;
struct macosx_event *stepping_event = NULL, *signal_event = NULL;
unsigned char retval;
macosx_low_debug (6, "Called macosx_wait_for_event\n");
inferior = get_thread_process (current_inferior);
macosx_clear_events (inferior);
event_count = 0;
keep_looking = 1;
first_time = 1;
while (keep_looking)
{
type = macosx_fetch_event (inferior, timeout, buf, &val);
if (first_time && type != MACOSX_SOURCE_EXITED)
{
first_time = 0;
macosx_check_new_threads (inferior);
macosx_exception_get_write_lock (inferior->status);
}
switch (type)
{
case MACOSX_SOURCE_EXITED:
*status = 'W';
macosx_exception_release_write_lock (inferior->status);
return val;
case MACOSX_SOURCE_SIGNALED:
*status = 'X';
macosx_exception_release_write_lock (inferior->status);
return val;
case MACOSX_SOURCE_STOPPED:
{
struct macosx_event *event;
warning ("Got stopped on signal not from SOFTEXC.\n");
event = macosx_add_to_events (inferior,
MACOSX_SOURCE_STOPPED,
(void *) val);
event_count++;
break;
}
case MACOSX_SOURCE_EXCEPTION:
{
struct macosx_event *event;
event = macosx_add_to_events (inferior,
MACOSX_SOURCE_EXCEPTION,
buf);
event_count++;
if (event->type == MACOSX_TYPE_SINGLESTEP)
stepping_event = event;
else if (event->type == MACOSX_TYPE_SIGNAL)
signal_event = event;
break;
}
case MACOSX_SOURCE_NONE:
keep_looking = 0;
break;
case MACOSX_SOURCE_ERROR:
warning ("Got an error fetching events.");
*status = 'W';
macosx_exception_release_write_lock (inferior->status);
return val;
}
timeout = 0;
}
macosx_exception_release_write_lock (inferior->status);
if (event_count == 1)
{
switch (macosx_event_chain->source)
{
case MACOSX_SOURCE_EXCEPTION:
{
*status = 'T';
retval = macosx_service_event (inferior, macosx_event_chain);
break;
}
case MACOSX_SOURCE_STOPPED:
{
*status = 'T';
retval = (int) macosx_event_chain->data;
break;
}
default:
error ("Only handling exceptions here");
}
}
else if (stepping_event != NULL)
{
macosx_low_debug (6, "More than one event, with stepping event.\n");
macosx_backup_threads_before_break (stepping_event);
retval = macosx_service_event (inferior, stepping_event);
*status = 'T';
}
else if (signal_event != NULL)
{
macosx_backup_threads_before_break (NULL);
retval = macosx_service_event (inferior, signal_event);
*status = 'T';
}
else
{
struct macosx_event *event_ptr;
int random_selector, nevents;
nevents = 0;
for (event_ptr = macosx_event_chain; event_ptr != NULL;
event_ptr = event_ptr->next)
{
if (event_ptr->source == MACOSX_SOURCE_EXCEPTION
&& event_ptr->type == MACOSX_TYPE_BREAKPOINT)
nevents++;
}
random_selector = (int) ((nevents * (double) rand ()) / (RAND_MAX + 1.0));
for (event_ptr = macosx_event_chain; event_ptr != NULL;
event_ptr = event_ptr->next)
{
if (random_selector == 0)
break;
else
random_selector--;
}
macosx_backup_threads_before_break (event_ptr);
retval = macosx_service_event (inferior, event_ptr);
*status = 'T';
}
macosx_clear_events ();
return retval;
}
static unsigned char
macosx_wait (char *status)
{
unsigned char w;
struct thread_info *child = NULL;
enable_async_io ();
unblock_async_io ();
w = macosx_wait_for_event (child, status, -1);
disable_async_io ();
terminal_ours ();
macosx_low_debug (6, "Called macosx_wait\n");
return (unsigned char) w;
}
static void
macosx_fetch_registers (int regno)
{
struct macosx_process_info *inferior;
inferior = get_thread_process (current_inferior);
the_low_target.low_fetch_registers (regno);
macosx_low_debug (6, "Called macosx_fetch_registers (%d)\n", regno);
}
static void
macosx_store_registers (int regno)
{
struct macosx_process_info *inferior;
inferior = get_thread_process (current_inferior);
the_low_target.low_store_registers (regno);
macosx_low_debug (6, "Called macosx_store_registers (%d)\n", regno);
}
static int
macosx_read_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len)
{
struct macosx_process_info *inferior;
int result;
inferior = get_thread_process (current_inferior);
result = mach_xfer_memory (memaddr, myaddr, len, 0, inferior->status->task);
macosx_low_debug (6, "Called macosx_read_memory\n");
if (result > 0)
return 0;
else
return errno;
}
static int
macosx_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len)
{
struct macosx_process_info *inferior;
int result;
inferior = get_thread_process (current_inferior);
result = mach_xfer_memory (memaddr, myaddr, len, 1, inferior->status->task);
macosx_low_debug (6, "Called macosx_write_memory\n");
if (result > 0)
return 0;
else
return errno;
}
static void
macosx_lookup_symbols (void)
{
macosx_low_debug (6, "UNIMPLEMENTED: Called macosx_lookup_symbols\n");
}
static void
macosx_send_signal (int signum)
{
macosx_low_debug (6, "Called macosx_send_signal -> kill (%d, %d);\n",
signal_pid, signum);
last_sent_signal = signum;
kill (signal_pid, signum);
}
static int
macosx_read_auxv (CORE_ADDR offset, unsigned char *myaddr, unsigned int len)
{
macosx_low_debug (6, "UNIMPLEMENTED: Called macosx_read_auxv\n");
return 0;
}
int
macosx_insert_watchpoint (char type, CORE_ADDR addr, int len)
{
return 1;
}
int
macosx_remove_watchpoint (char type, CORE_ADDR addr, int len)
{
return 1;
}
int
macosx_stopped_by_watchpoint (void)
{
return 0;
}
CORE_ADDR
macosx_stopped_data_address (void)
{
return 0;
}
static int
gdbserver_has_a_terminal (void)
{
static enum
{
no = 0, yes = 1, have_not_checked = 2
}
we_have_a_terminal = have_not_checked;
switch (we_have_a_terminal)
{
case no:
return 0;
case yes:
return 1;
case have_not_checked:
we_have_a_terminal = no;
if (isatty (STDIN_FILENO))
{
our_tflags = fcntl (STDIN_FILENO, F_GETFL, 0);
our_ttystate_err = tcgetattr (STDIN_FILENO, &our_ttystate);
if (our_ttystate_err == 0)
{
we_have_a_terminal = yes;
our_process_group = tcgetpgrp (0);
}
}
macosx_low_debug (6, "%s () => %d\n", __FUNCTION__,
we_have_a_terminal == yes);
return we_have_a_terminal == yes;
default:
break;
}
return 0;
}
static void
terminal_inferior (void)
{
if (gdbserver_has_a_terminal () && terminal_is_ours &&
inferior_ttystate_err == 0)
{
int result;
result = fcntl (STDIN_FILENO, F_SETFL, inferior_tflags);
result = tcsetattr (STDIN_FILENO, TCSANOW, &inferior_ttystate);
if (inferior_process_group >= 0)
result = tcsetpgrp (STDIN_FILENO, inferior_process_group);
}
terminal_is_ours = 0;
}
static void
terminal_ours (void)
{
if (gdbserver_has_a_terminal () == 0)
return;
if (terminal_is_ours == 0)
{
void (*osigttou) () = NULL;
int result;
terminal_is_ours = 1;
osigttou = (void (*)()) signal (SIGTTOU, SIG_IGN);
inferior_ttystate_err = tcgetattr (STDIN_FILENO, &inferior_ttystate);
if (attached_to_process)
inferior_process_group = -1;
else
inferior_process_group = tcgetpgrp (0);
inferior_tflags = fcntl (STDIN_FILENO, F_GETFL, 0);
result = tcsetattr (STDIN_FILENO, TCSANOW, &our_ttystate);
if (our_process_group >= 0)
result = tcsetpgrp (STDIN_FILENO, our_process_group);
result = fcntl (STDIN_FILENO, F_SETFL, our_tflags);
signal (SIGTTOU, osigttou);
}
}
static struct target_ops macosx_target_ops = {
macosx_create_inferior,
macosx_attach,
macosx_kill,
macosx_detach,
macosx_thread_alive,
macosx_resume,
macosx_wait,
macosx_fetch_registers,
macosx_store_registers,
macosx_read_memory,
macosx_write_memory,
macosx_lookup_symbols,
macosx_send_signal,
macosx_read_auxv,
macosx_insert_watchpoint,
macosx_remove_watchpoint,
macosx_stopped_by_watchpoint,
macosx_stopped_data_address
};
int using_threads;
int debug_threads;
void
initialize_low (void)
{
using_threads = 1;
set_target_ops (&macosx_target_ops);
init_registers ();
signal (SIGCHLD, sigchld_handler);
#if 0
linux_init_signals ();
#endif
}