/* Interface GDB to the GNU Hurd.
- Copyright 1992, 1995, 1996, 1997, 1998, 1999, 2000
+ Copyright 1992, 1995, 1996, 1997, 1998, 1999, 2000, 2001
Free Software Foundation, Inc.
This file is part of GDB.
Boston, MA 02111-1307, USA.
*/
+#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <setjmp.h>
#include <signal.h>
#include <stdio.h>
-#include <string.h>
+#include "gdb_string.h"
#include <sys/ptrace.h>
#include <mach.h>
proc_debug (proc, "is %s", err ? "dead" : running ? "running" : "suspended");
if (err)
- proc_debug (proc, "err = %s", strerror (err));
+ proc_debug (proc, "err = %s", safe_strerror (err));
if (running)
{
proc->exc_port = exc_port;
else
warning ("Error setting exception port for %s: %s",
- proc_string (proc), strerror (err));
+ proc_string (proc), safe_strerror (err));
}
}
proc->exc_port = MACH_PORT_NULL;
else
warning ("Error setting exception port for %s: %s",
- proc_string (proc), strerror (err));
+ proc_string (proc), safe_strerror (err));
}
}
&prev_port);
if (err)
warning ("Couldn't request notification for port %d: %s",
- port, strerror (err));
+ port, safe_strerror (err));
else
{
proc_debug (proc, "notifications to: %d", inf->event_port);
err = mach_port_allocate (mach_task_self (),
MACH_PORT_RIGHT_RECEIVE, &inf->event_port);
if (err)
- error ("Error allocating event port: %s", strerror (err));
+ error ("Error allocating event port: %s", safe_strerror (err));
/* Make a send right for it, so we can easily copy it for other people. */
mach_port_insert_right (mach_task_self (), inf->event_port,
{
error_t err = proc_pid2task (proc_server, pid, &task_port);
if (err)
- error ("Error getting task for pid %d: %s", pid, strerror (err));
+ error ("Error getting task for pid %d: %s", pid, safe_strerror (err));
}
inf_debug (inf, "setting task: %d", task_port);
}
else if (err)
warning ("Can't modify tracing state for pid %d: %s",
- inf->pid, strerror (err));
+ inf->pid, safe_strerror (err));
else
inf->traced = on;
}
(last ? last->next : inf->threads) = thread;
last = thread;
proc_debug (thread, "new thread: %d", threads[i]);
- add_thread (thread->tid); /* Tell GDB's generic thread code. */
+ add_thread (pid_to_ptid (thread->tid)); /* Tell GDB's generic thread code. */
}
}
/* Can't do too much... */
warning ("Can't deliver signal %s: No signal thread.", NAME);
else if (err)
- warning ("Delivering signal %s: %s", NAME, strerror (err));
+ warning ("Delivering signal %s: %s", NAME, safe_strerror (err));
#undef NAME
}
}
if (err)
- warning ("Can't continue process: %s", strerror (err));
+ warning ("Can't continue process: %s", safe_strerror (err));
}
\f
struct inf *waiting_inf;
/* Wait for something to happen in the inferior, returning what in STATUS. */
-static int
-gnu_wait (int tid, struct target_waitstatus *status)
+static ptid_t
+gnu_wait (ptid_t tid, struct target_waitstatus *status)
{
struct msg
{
waiting_inf = inf;
- inf_debug (inf, "waiting for: %d", tid);
+ inf_debug (inf, "waiting for: %d", PIDGET (tid));
rewait:
if (proc_wait_pid != inf->pid && !inf->no_wait)
err =
proc_wait_request (proc_server, inf->event_port, inf->pid, WUNTRACED);
if (err)
- warning ("wait request failed: %s", strerror (err));
+ warning ("wait request failed: %s", safe_strerror (err));
else
{
inf_debug (inf, "waits pending: %d", proc_waits_pending);
if (err == EMACH_RCV_INTERRUPTED)
inf_debug (inf, "interrupted");
else if (err)
- error ("Couldn't wait for an event: %s", strerror (err));
+ error ("Couldn't wait for an event: %s", safe_strerror (err));
else
{
struct
if (reply.err)
error ("Handling event, msgid = %d: %s",
- msg.hdr.msgh_id, strerror (reply.err));
+ msg.hdr.msgh_id, safe_strerror (reply.err));
}
if (inf->pending_execs)
thread = inf->wait.thread;
if (thread)
- tid = thread->tid;
+ tid = pid_to_ptid (thread->tid);
else
- thread = inf_tid_to_thread (inf, tid);
+ thread = inf_tid_to_thread (inf, PIDGET (tid));
if (!thread || thread->port == MACH_PORT_NULL)
{
/* TID is dead; try and find a new thread. */
if (inf_update_procs (inf) && inf->threads)
- tid = inf->threads->tid; /* The first available thread. */
+ tid = pid_to_ptid (inf->threads->tid); /* The first available thread. */
else
- tid = inferior_pid; /* let wait_for_inferior handle exit case */
+ tid = inferior_ptid; /* let wait_for_inferior handle exit case */
}
- if (thread && tid >= 0 && status->kind != TARGET_WAITKIND_SPURIOUS
+ if (thread && PIDGET (tid) >= 0 && status->kind != TARGET_WAITKIND_SPURIOUS
&& inf->pause_sc == 0 && thread->pause_sc == 0)
/* If something actually happened to THREAD, make sure we
suspend it. */
inf_update_suspends (inf);
}
- inf_debug (inf, "returning tid = %d, status = %s (%d)", tid,
+ inf_debug (inf, "returning tid = %d, status = %s (%d)", PIDGET (tid),
status->kind == TARGET_WAITKIND_EXITED ? "EXITED"
: status->kind == TARGET_WAITKIND_STOPPED ? "STOPPED"
: status->kind == TARGET_WAITKIND_SIGNALLED ? "SIGNALLED"
struct inf *inf = waiting_inf;
inf_debug (inf, "err = %s, pid = %d, status = 0x%x, sigcode = %d",
- err ? strerror (err) : "0", pid, status, sigcode);
+ err ? safe_strerror (err) : "0", pid, status, sigcode);
if (err && proc_wait_pid && (!inf->task || !inf->task->port))
/* Ack. The task has died, but the task-died notification code didn't
{
if (err != EINTR)
{
- warning ("Can't wait for pid %d: %s", inf->pid, strerror (err));
+ warning ("Can't wait for pid %d: %s", inf->pid, safe_strerror (err));
inf->no_wait = 1;
/* Since we can't see the inferior's signals, don't trap them. */
inf->wait.status.value.sig = TARGET_SIGNAL_0;
}
else if (err)
- warning ("Signal delivery failed: %s", strerror (err));
+ warning ("Signal delivery failed: %s", safe_strerror (err));
if (err)
/* We only get this reply when we've posted a signal to a process which we
in multiple events returned by wait).
*/
static void
-gnu_resume (int tid, int step, enum target_signal sig)
+gnu_resume (ptid_t tid, int step, enum target_signal sig)
{
struct proc *step_thread = 0;
struct inf *inf = current_inferior;
- inf_debug (inf, "tid = %d, step = %d, sig = %d", tid, step, sig);
+ inf_debug (inf, "tid = %d, step = %d, sig = %d", PIDGET (tid), step, sig);
inf_validate_procinfo (inf);
inf_update_procs (inf);
- if (tid < 0)
+ if (PIDGET (tid) < 0)
/* Allow all threads to run, except perhaps single-stepping one. */
{
- inf_debug (inf, "running all threads; tid = %d", inferior_pid);
- tid = inferior_pid; /* What to step. */
+ inf_debug (inf, "running all threads; tid = %d", PIDGET (inferior_ptid));
+ tid = inferior_ptid; /* What to step. */
inf_set_threads_resume_sc (inf, 0, 1);
}
else
/* Just allow a single thread to run. */
{
- struct proc *thread = inf_tid_to_thread (inf, tid);
+ struct proc *thread = inf_tid_to_thread (inf, PIDGET (tid));
if (!thread)
error ("Can't run single thread id %d: no such thread!");
inf_debug (inf, "running one thread: %d/%d", inf->pid, thread->tid);
if (step)
{
- step_thread = inf_tid_to_thread (inf, tid);
+ step_thread = inf_tid_to_thread (inf, PIDGET (tid));
if (!step_thread)
- warning ("Can't step thread id %d: no such thread.", tid);
+ warning ("Can't step thread id %d: no such thread.", PIDGET (tid));
else
inf_debug (inf, "stepping thread: %d/%d", inf->pid, step_thread->tid);
}
/* Now let the child run again, knowing that it will stop immediately
because of the ptrace. */
inf_resume (inf);
- inferior_pid = inf_pick_first_thread ();
+ inferior_ptid = pid_to_ptid (inf_pick_first_thread ());
startup_inferior (inf->pending_execs);
}
inf_attach (inf, pid);
inf_update_procs (inf);
- inferior_pid = inf_pick_first_thread ();
+ inferior_ptid = pid_to_ptid (inf_pick_first_thread ());
attach_flag = 1;
push_target (&gnu_ops);
inf_detach (current_inferior);
- inferior_pid = 0;
+ inferior_ptid = null_ptid;
unpush_target (&gnu_ops); /* Pop out of handling an inferior */
}
}
static char *
-gnu_pid_to_exec_file (void)
+gnu_pid_to_exec_file (int pid)
{
error ("to_pid_to_exec_file target function not implemented");
return NULL;
static int
-gnu_thread_alive (int tid)
+gnu_thread_alive (ptid_t tid)
{
inf_update_procs (current_inferior);
- return !!inf_tid_to_thread (current_inferior, tid);
+ return !!inf_tid_to_thread (current_inferior, PIDGET (tid));
}
\f
err = hurd_safe_copyin (myaddr, (void *) addr - low_address + copied, length);
if (err)
{
- warning ("Read from inferior faulted: %s", strerror (err));
+ warning ("Read from inferior faulted: %s", safe_strerror (err));
length = 0;
}
err = vm_deallocate (mach_task_self (), copied, copy_count);
if (err)
- warning ("gnu_read_inferior vm_deallocate failed: %s", strerror (err));
+ warning ("gnu_read_inferior vm_deallocate failed: %s", safe_strerror (err));
return length;
}
else
{
inf_debug (current_inferior, "%s %p[%d] %s %p",
- write ? "writing" : "reading", memaddr, len,
+ write ? "writing" : "reading", (void *) memaddr, len,
write ? "<--" : "-->", myaddr);
if (write)
return gnu_write_inferior (task, memaddr, myaddr, len);
}
}
+/* Call FUNC on each memory region in the task. */
+static int
+gnu_find_memory_regions (int (*func) (CORE_ADDR,
+ unsigned long,
+ int, int, int,
+ void *),
+ void *data)
+{
+ error_t err;
+ task_t task;
+ vm_address_t region_address, last_region_address, last_region_end;
+ vm_prot_t last_protection;
+
+ if (current_inferior == 0 || current_inferior->task == 0)
+ return 0;
+ task = current_inferior->task->port;
+ if (task == MACH_PORT_NULL)
+ return 0;
+
+ region_address = last_region_address = last_region_end = VM_MIN_ADDRESS;
+ last_protection = VM_PROT_NONE;
+ while (region_address < VM_MAX_ADDRESS)
+ {
+ vm_prot_t protection;
+ vm_prot_t max_protection;
+ vm_inherit_t inheritance;
+ boolean_t shared;
+ mach_port_t object_name;
+ vm_offset_t offset;
+ vm_size_t region_length = VM_MAX_ADDRESS - region_address;
+ vm_address_t old_address = region_address;
+
+ err = vm_region (task,
+ ®ion_address,
+ ®ion_length,
+ &protection,
+ &max_protection,
+ &inheritance,
+ &shared,
+ &object_name,
+ &offset);
+ if (err == KERN_NO_SPACE)
+ break;
+ if (err != KERN_SUCCESS)
+ {
+ warning ("vm_region failed: %s", mach_error_string (err));
+ return -1;
+ }
+
+ if (protection == last_protection && region_address == last_region_end)
+ /* This region is contiguous with and indistinguishable from
+ the previous one, so we just extend that one. */
+ last_region_end = region_address += region_length;
+ else
+ {
+ /* This region is distinct from the last one we saw, so report
+ that previous one. */
+ if (last_protection != VM_PROT_NONE)
+ (*func) (last_region_address,
+ last_region_end - last_region_address,
+ last_protection & VM_PROT_READ,
+ last_protection & VM_PROT_WRITE,
+ last_protection & VM_PROT_EXECUTE,
+ data);
+ last_region_address = region_address;
+ last_region_end = region_address += region_length;
+ last_protection = protection;
+ }
+ }
+
+ /* Report the final region. */
+ if (last_region_end > last_region_address && last_protection != VM_PROT_NONE)
+ (*func) (last_region_address, last_region_end - last_region_address,
+ last_protection & VM_PROT_READ,
+ last_protection & VM_PROT_WRITE,
+ last_protection & VM_PROT_EXECUTE,
+ data);
+
+ return 0;
+}
+
\f
/* Return printable description of proc. */
char *
sprintf (tid_str, "process %d", proc->inf->pid);
else
sprintf (tid_str, "thread %d.%d",
- proc->inf->pid, pid_to_thread_id (proc->tid));
+ proc->inf->pid, pid_to_thread_id (MERGEPID (proc->tid, 0)));
return tid_str;
}
static char *
-gnu_pid_to_str (int tid)
+gnu_pid_to_str (ptid_t ptid)
{
struct inf *inf = current_inferior;
+ int tid = PIDGET (ptid);
struct proc *thread = inf_tid_to_thread (inf, tid);
if (thread)
gnu_ops.to_store_registers = gnu_store_registers; /* to_store_registers */
gnu_ops.to_prepare_to_store = gnu_prepare_to_store; /* to_prepare_to_store */
gnu_ops.to_xfer_memory = gnu_xfer_memory; /* to_xfer_memory */
+ gnu_ops.to_find_memory_regions = gnu_find_memory_regions;
gnu_ops.to_files_info = 0; /* to_files_info */
gnu_ops.to_insert_breakpoint = memory_insert_breakpoint;
gnu_ops.to_remove_breakpoint = memory_remove_breakpoint;
gnu_ops.to_pid_to_str = gnu_pid_to_str; /* to_pid_to_str */
gnu_ops.to_stop = gnu_stop; /* to_stop */
gnu_ops.to_pid_to_exec_file = gnu_pid_to_exec_file; /* to_pid_to_exec_file */
- gnu_ops.to_core_file_to_sym_file = NULL;
gnu_ops.to_stratum = process_stratum; /* to_stratum */
gnu_ops.DONT_USE = 0; /* to_next */
gnu_ops.to_has_all_memory = 1; /* to_has_all_memory */
cur_thread (void)
{
struct inf *inf = cur_inf ();
- struct proc *thread = inf_tid_to_thread (inf, inferior_pid);
+ struct proc *thread = inf_tid_to_thread (inf, PIDGET (inferior_ptid));
if (!thread)
error ("No current thread.");
return thread;
&port, &port_type);
if (err)
error ("Couldn't extract send right %d from inferior: %s",
- name, strerror (err));
+ name, safe_strerror (err));
if (proc->saved_exc_port)
/* Get rid of our reference to the old one. */
proc->exc_port = proc->inf->event_port;
err = proc_set_exception_port (proc, proc->exc_port);
error ("Can't set exception port for %s: %s",
- proc_string (proc), strerror (err));
+ proc_string (proc), safe_strerror (err));
}
}
inf->signal_thread = 0;
else
{
- int tid = thread_id_to_pid (atoi (args));
+ int tid = PIDGET (thread_id_to_pid (atoi (args)));
if (tid < 0)
error ("Thread ID %s not known. Use the \"info threads\" command to\n"
"see the IDs of currently known threads.", args);
info_port_rights (char *args, mach_port_type_t only)
{
struct inf *inf = active_inf ();
- value_ptr vmark = value_mark ();
+ struct value *vmark = value_mark ();
if (args)
/* Explicit list of port rights. */
{
while (*args)
{
- value_ptr val = parse_to_comma_and_eval (&args);
+ struct value *val = parse_to_comma_and_eval (&args);
long right = value_as_long (val);
error_t err =
print_port_info (right, 0, inf->task->port, PORTINFO_DETAILS,
stdout);
if (err)
- error ("%ld: %s.", right, strerror (err));
+ error ("%ld: %s.", right, safe_strerror (err));
}
}
else
print_task_ports_info (inf->task->port, only, PORTINFO_DETAILS,
stdout);
if (err)
- error ("%s.", strerror (err));
+ error ("%s.", safe_strerror (err));
}
value_free_to_mark (vmark);
error_t err =
thread_info (thread->port, THREAD_BASIC_INFO, (int *) &info, &info_len);
if (err)
- error ("%s.", strerror (err));
+ error ("%s.", safe_strerror (err));
thread->sc = info->suspend_count;
if (from_tty)
printf_unfiltered ("Suspend count was %d.\n", thread->sc);
MATTR_CACHE,
&flush);
if (ret != KERN_SUCCESS)
- warning ("Error flushing inferior's cache : %s", strerror (ret));
+ warning ("Error flushing inferior's cache : %s", safe_strerror (ret));
}
#endif /* FLUSH_INFERIOR_CACHE */