#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <unistd.h>
#include <sys/sysctl.h>
#include <signal.h>
#include <sys/un.h>
#include <sys/stat.h>
#include "bfd.h"
#include "defs.h"
#include "gdbcore.h"
#include "serial.h"
#include "ser-base.h"
#include "ser-unix.h"
#include "inferior.h"
#include "objc-lang.h"
#include "infcall.h"
#include "macosx-nat-dyld.h"
#include "macosx-nat-dyld-info.h"
#include "macosx-nat-inferior.h"
#include "macosx-nat-dyld-process.h"
extern macosx_inferior_status *macosx_status;
extern macosx_dyld_thread_status macosx_dyld_status;
extern int inferior_auto_start_cfm_flag;
extern int inferior_auto_start_dyld_flag;
static void
macosx_classic_unix_close (struct serial *scb)
{
if (scb->fd < 0)
return;
close (scb->fd);
scb->fd = -1;
}
static int
macosx_classic_unix_open (struct serial *scb, const char *name)
{
struct sockaddr_un sockaddr;
int n;
if (strncmp (name, "unix:", 5) != 0)
return -1;
name += 5;
scb->fd = socket (PF_UNIX, SOCK_STREAM, 0);
if (scb->fd == -1)
return -1;
sockaddr.sun_family = PF_UNIX;
strcpy (sockaddr.sun_path, name);
sockaddr.sun_len = sizeof (sockaddr);
n = connect (scb->fd, (struct sockaddr *)&sockaddr, sizeof (sockaddr));
if (n == -1)
{
macosx_classic_unix_close (scb);
return -1;
}
signal (SIGPIPE, SIG_IGN);
return 0;
}
static void
macosx_classic_deliver_signal (int sig)
{
printf_filtered ("sending signal %d to pid %d\n", sig, macosx_status->pid);
kill (macosx_status->pid, sig);
}
static void
macosx_classic_stop_inferior (void)
{
macosx_classic_deliver_signal (SIGINT);
}
static void
macosx_classic_create_inferior (pid_t pid)
{
int kr;
task_t task;
kr = task_for_pid (mach_task_self (), pid, &task);
if (kr != KERN_SUCCESS)
{
error ("task_for_pid failed for pid %d: %s", pid,
mach_error_string (kr));
}
else
{
macosx_create_inferior_for_task (macosx_status, task, pid);
printf_filtered ("pid %d -> mach task %d\n", macosx_status->pid,
macosx_status->task);
if (inferior_auto_start_dyld_flag)
{
int i;
struct dyld_objfile_entry *e;
DYLD_ALL_OBJFILE_INFO_ENTRIES (&macosx_dyld_status.current_info, e, i)
{
dyld_remove_objfile (e);
dyld_objfile_entry_clear (e);
}
macosx_dyld_init (&macosx_dyld_status, exec_bfd);
DYLD_ALL_OBJFILE_INFO_ENTRIES (&macosx_dyld_status.current_info, e, i)
{
dyld_remove_objfile (e);
dyld_objfile_entry_clear (e);
}
macosx_dyld_update (1);
}
#if WITH_CFM
if (inferior_auto_start_cfm_flag)
{
macosx_cfm_thread_init (&macosx_status->cfm_status);
}
#endif
}
}
static int
classic_socket_exists_p (pid_t pid)
{
char name[PATH_MAX];
struct stat sb;
sprintf (name, "/tmp/translate.gdb.%d", pid);
if (stat (name, &sb) != 0)
return 0;
if (sb.st_mode & S_IFSOCK)
return 1;
return 0;
}
int
is_pid_classic (pid_t pid)
{
int mib[] = { CTL_KERN, KERN_CLASSIC, pid };
size_t len = sizeof (int);
int ret = 0;
if (sysctl (mib, 3, &ret, &len, NULL, 0) == -1)
return -1;
return ret;
}
int
can_attach (pid_t target_pid)
{
int gdb_is_classic, target_is_classic;
target_is_classic = is_pid_classic (target_pid);
gdb_is_classic = is_pid_classic (getpid ());
if (gdb_is_classic == -1)
return 1;
if (gdb_is_classic == 1)
{
if (target_is_classic == 1)
target_is_classic = classic_socket_exists_p (target_pid);
if (target_is_classic == 1)
return 1;
if (target_is_classic == 0)
return 0;
if (target_is_classic == -1)
return 0;
}
if (gdb_is_classic == 0)
{
if (target_is_classic == 0)
return 1;
if (target_is_classic == -1)
return 1;
}
return 1;
}
int
attaching_to_classic_process_p (pid_t target_pid)
{
int gdb_is_classic, target_is_classic;
target_is_classic = is_pid_classic (target_pid);
gdb_is_classic = is_pid_classic (getpid ());
if (gdb_is_classic == 1 && target_is_classic == 1)
return 1;
return 0;
}
extern struct target_ops remote_ops;
void
attach_to_classic_process (pid_t pid)
{
char name[PATH_MAX];
sprintf (name, "unix:/tmp/translate.gdb.%d", pid);
push_remote_target (name, 0);
macosx_classic_create_inferior (pid);
remote_ops.to_stop = macosx_classic_stop_inferior;
inferior_function_calls_disabled_p = 1;
lookup_objc_class_p = 0;
update_current_target ();
}
void
_initialize_macosx_nat ()
{
struct rlimit limit;
rlim_t reserve;
getrlimit (RLIMIT_NOFILE, &limit);
limit.rlim_cur = limit.rlim_max;
setrlimit (RLIMIT_NOFILE, &limit);
reserve = (int) limit.rlim_max * 0.1;
reserve = (reserve > 5) ? reserve : 5;
if (reserve >= limit.rlim_max)
{
bfd_set_cache_max_open (1);
}
else
{
bfd_set_cache_max_open (limit.rlim_max - reserve);
}
struct serial_ops *ops = XMALLOC (struct serial_ops);
memset (ops, 0, sizeof (struct serial_ops));
ops->name = "unix";
ops->next = 0;
ops->open = macosx_classic_unix_open;
ops->close = macosx_classic_unix_close;
ops->readchar = ser_base_readchar;
ops->write = ser_base_write;
ops->flush_output = ser_base_flush_output;
ops->flush_input = ser_base_flush_input;
ops->send_break = ser_base_send_break;
ops->go_raw = ser_base_raw;
ops->get_tty_state = ser_base_get_tty_state;
ops->set_tty_state = ser_base_set_tty_state;
ops->print_tty_state = ser_base_print_tty_state;
ops->noflush_set_tty_state = ser_base_noflush_set_tty_state;
ops->setbaudrate = ser_base_setbaudrate;
ops->setstopbits = ser_base_setstopbits;
ops->drain_output = ser_base_drain_output;
ops->async = ser_base_async;
ops->read_prim = ser_unix_read_prim;
ops->write_prim = ser_unix_write_prim;
serial_add_interface (ops);
}