static ptid_t previous_inferior_ptid;
+/* Default behavior is to detach newly forked processes (legacy). */
+int detach_fork = 1;
+
int debug_displaced = 0;
static void
show_debug_displaced (struct ui_file *file, int from_tty,
insert_breakpoints ();
}
+/* The child has exited or execed: resume threads of the parent the
+ user wanted to be executing. */
+
+static int
+proceed_after_vfork_done (struct thread_info *thread,
+ void *arg)
+{
+ int pid = * (int *) arg;
+
+ if (ptid_get_pid (thread->ptid) == pid
+ && is_running (thread->ptid)
+ && !is_executing (thread->ptid)
+ && !thread->stop_requested
+ && thread->stop_signal == TARGET_SIGNAL_0)
+ {
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog,
+ "infrun: resuming vfork parent thread %s\n",
+ target_pid_to_str (thread->ptid));
+
+ switch_to_thread (thread->ptid);
+ clear_proceed_status ();
+ proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 0);
+ }
+
+ return 0;
+}
+
+/* Called whenever we notice an exec or exit event, to handle
+ detaching or resuming a vfork parent. */
+
+static void
+handle_vfork_child_exec_or_exit (int exec)
+{
+ struct inferior *inf = current_inferior ();
+
+ if (inf->vfork_parent)
+ {
+ int resume_parent = -1;
+
+ /* This exec or exit marks the end of the shared memory region
+ between the parent and the child. If the user wanted to
+ detach from the parent, now is the time. */
+
+ if (inf->vfork_parent->pending_detach)
+ {
+ struct thread_info *tp;
+ struct cleanup *old_chain;
+ struct program_space *pspace;
+ struct address_space *aspace;
+
+ /* follow-fork child, detach-on-fork on */
+
+ old_chain = make_cleanup_restore_current_thread ();
+
+ /* We're letting loose of the parent. */
+ tp = any_live_thread_of_process (inf->vfork_parent->pid);
+ switch_to_thread (tp->ptid);
+
+ /* We're about to detach from the parent, which implicitly
+ removes breakpoints from its address space. There's a
+ catch here: we want to reuse the spaces for the child,
+ but, parent/child are still sharing the pspace at this
+ point, although the exec in reality makes the kernel give
+ the child a fresh set of new pages. The problem here is
+ that the breakpoints module being unaware of this, would
+ likely chose the child process to write to the parent
+ address space. Swapping the child temporarily away from
+ the spaces has the desired effect. Yes, this is "sort
+ of" a hack. */
+
+ pspace = inf->pspace;
+ aspace = inf->aspace;
+ inf->aspace = NULL;
+ inf->pspace = NULL;
+
+ if (debug_infrun || info_verbose)
+ {
+ target_terminal_ours ();
+
+ if (exec)
+ fprintf_filtered (gdb_stdlog,
+ "Detaching vfork parent process %d after child exec.\n",
+ inf->vfork_parent->pid);
+ else
+ fprintf_filtered (gdb_stdlog,
+ "Detaching vfork parent process %d after child exit.\n",
+ inf->vfork_parent->pid);
+ }
+
+ target_detach (NULL, 0);
+
+ /* Put it back. */
+ inf->pspace = pspace;
+ inf->aspace = aspace;
+
+ do_cleanups (old_chain);
+ }
+ else if (exec)
+ {
+ /* We're staying attached to the parent, so, really give the
+ child a new address space. */
+ inf->pspace = add_program_space (maybe_new_address_space ());
+ inf->aspace = inf->pspace->aspace;
+ inf->removable = 1;
+ set_current_program_space (inf->pspace);
+
+ resume_parent = inf->vfork_parent->pid;
+
+ /* Break the bonds. */
+ inf->vfork_parent->vfork_child = NULL;
+ }
+ else
+ {
+ struct cleanup *old_chain;
+ struct program_space *pspace;
+
+ /* If this is a vfork child exiting, then the pspace and
+ aspaces were shared with the parent. Since we're
+ reporting the process exit, we'll be mourning all that is
+ found in the address space, and switching to null_ptid,
+ preparing to start a new inferior. But, since we don't
+ want to clobber the parent's address/program spaces, we
+ go ahead and create a new one for this exiting
+ inferior. */
+
+ /* Switch to null_ptid, so that clone_program_space doesn't want
+ to read the selected frame of a dead process. */
+ old_chain = save_inferior_ptid ();
+ inferior_ptid = null_ptid;
+
+ /* This inferior is dead, so avoid giving the breakpoints
+ module the option to write through to it (cloning a
+ program space resets breakpoints). */
+ inf->aspace = NULL;
+ inf->pspace = NULL;
+ pspace = add_program_space (maybe_new_address_space ());
+ set_current_program_space (pspace);
+ inf->removable = 1;
+ clone_program_space (pspace, inf->vfork_parent->pspace);
+ inf->pspace = pspace;
+ inf->aspace = pspace->aspace;
+
+ /* Put back inferior_ptid. We'll continue mourning this
+ inferior. */
+ do_cleanups (old_chain);
+
+ resume_parent = inf->vfork_parent->pid;
+ /* Break the bonds. */
+ inf->vfork_parent->vfork_child = NULL;
+ }
+
+ inf->vfork_parent = NULL;
+
+ gdb_assert (current_program_space == inf->pspace);
+
+ if (non_stop && resume_parent != -1)
+ {
+ /* If the user wanted the parent to be running, let it go
+ free now. */
+ struct cleanup *old_chain = make_cleanup_restore_current_thread ();
+
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog, "infrun: resuming vfork parent process %d\n",
+ resume_parent);
+
+ iterate_over_threads (proceed_after_vfork_done, &resume_parent);
+
+ do_cleanups (old_chain);
+ }
+ }
+}
+
+/* Enum strings for "set|show displaced-stepping". */
+
+static const char follow_exec_mode_new[] = "new";
+static const char follow_exec_mode_same[] = "same";
+static const char *follow_exec_mode_names[] =
+{
+ follow_exec_mode_new,
+ follow_exec_mode_same,
+ NULL,
+};
+
+static const char *follow_exec_mode_string = follow_exec_mode_same;
+static void
+show_follow_exec_mode_string (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c, const char *value)
+{
+ fprintf_filtered (file, _("Follow exec mode is \"%s\".\n"), value);
+}
+
/* EXECD_PATHNAME is assumed to be non-NULL. */
static void
{
struct target_ops *tgt;
struct thread_info *th = inferior_thread ();
+ struct inferior *inf = current_inferior ();
/* This is an exec event that we actually wish to pay attention to.
Refresh our symbol table to the newly exec'd program, remove any
that may write the bp's "shadow contents" (the instruction
value that was overwritten witha TRAP instruction). Since
we now have a new a.out, those shadow contents aren't valid. */
+
+ mark_breakpoints_out ();
+
update_breakpoints_after_exec ();
/* If there was one, it's gone now. We cannot truly step-to-next
th->stop_requested = 0;
/* What is this a.out's name? */
- printf_unfiltered (_("Executing new program: %s\n"), execd_pathname);
+ printf_unfiltered (_("%s is executing new program: %s\n"),
+ target_pid_to_str (inferior_ptid),
+ execd_pathname);
/* We've followed the inferior through an exec. Therefore, the
inferior has essentially been killed & reborn. */
execd_pathname = name;
}
- /* That a.out is now the one to use. */
- exec_file_attach (execd_pathname, 0);
-
/* Reset the shared library package. This ensures that we get a
shlib event when the child reaches "_start", at which point the
dld will have had a chance to initialize the child. */
previous incarnation of this process. */
no_shared_libraries (NULL, 0);
+ if (follow_exec_mode_string == follow_exec_mode_new)
+ {
+ struct program_space *pspace;
+ struct inferior *new_inf;
+
+ /* The user wants to keep the old inferior and program spaces
+ around. Create a new fresh one, and switch to it. */
+
+ inf = add_inferior (current_inferior ()->pid);
+ pspace = add_program_space (maybe_new_address_space ());
+ inf->pspace = pspace;
+ inf->aspace = pspace->aspace;
+
+ exit_inferior_num_silent (current_inferior ()->num);
+
+ set_current_inferior (inf);
+ set_current_program_space (pspace);
+ }
+
+ gdb_assert (current_program_space == inf->pspace);
+
+ /* That a.out is now the one to use. */
+ exec_file_attach (execd_pathname, 0);
+
/* Load the main file's symbols. */
symbol_file_add_main (execd_pathname, 0);
struct regcache *regcache;
struct gdbarch *gdbarch;
CORE_ADDR actual_pc;
+ struct address_space *aspace;
head = displaced_step_request_queue;
ptid = head->ptid;
regcache = get_thread_regcache (ptid);
actual_pc = regcache_read_pc (regcache);
+ aspace = get_regcache_aspace (regcache);
- if (breakpoint_here_p (actual_pc))
+ if (breakpoint_here_p (aspace, actual_pc))
{
if (debug_displaced)
fprintf_unfiltered (gdb_stdlog,
struct gdbarch *gdbarch = get_regcache_arch (regcache);
struct thread_info *tp = inferior_thread ();
CORE_ADDR pc = regcache_read_pc (regcache);
+ struct address_space *aspace = get_regcache_aspace (regcache);
QUIT;
removed or inserted, as appropriate. The exception is if we're sitting
at a permanent breakpoint; we need to step over it, but permanent
breakpoints can't be removed. So we have to test for it here. */
- if (breakpoint_here_p (pc) == permanent_breakpoint_here)
+ if (breakpoint_here_p (aspace, pc) == permanent_breakpoint_here)
{
if (gdbarch_skip_permanent_breakpoint_p (gdbarch))
gdbarch_skip_permanent_breakpoint (gdbarch, regcache);
/* Most targets can step a breakpoint instruction, thus
executing it normally. But if this one cannot, just
continue and we will hit it anyway. */
- if (step && breakpoint_inserted_here_p (pc))
+ if (step && breakpoint_inserted_here_p (aspace, pc))
step = 0;
}
void
clear_proceed_status (void)
{
+ if (!non_stop)
+ {
+ /* In all-stop mode, delete the per-thread status of all
+ threads, even if inferior_ptid is null_ptid, there may be
+ threads on the list. E.g., we may be launching a new
+ process, while selecting the executable. */
+ iterate_over_threads (clear_proceed_status_callback, NULL);
+ }
+
if (!ptid_equal (inferior_ptid, null_ptid))
{
struct inferior *inferior;
if (non_stop)
{
- /* If in non-stop mode, only delete the per-thread status
- of the current thread. */
+ /* If in non-stop mode, only delete the per-thread status of
+ the current thread. */
clear_proceed_status_thread (inferior_thread ());
}
- else
- {
- /* In all-stop mode, delete the per-thread status of
- *all* threads. */
- iterate_over_threads (clear_proceed_status_callback, NULL);
- }
-
+
inferior = current_inferior ();
inferior->stop_soon = NO_STOP_QUIETLY;
}
{
struct regcache *regcache = get_thread_regcache (wait_ptid);
- if (breakpoint_here_p (regcache_read_pc (regcache)))
+ if (breakpoint_here_p (get_regcache_aspace (regcache),
+ regcache_read_pc (regcache)))
{
/* If stepping, remember current thread to switch back to. */
if (step)
struct gdbarch *gdbarch;
struct thread_info *tp;
CORE_ADDR pc;
+ struct address_space *aspace;
int oneproc = 0;
/* If we're stopped at a fork/vfork, follow the branch set by the
regcache = get_current_regcache ();
gdbarch = get_regcache_arch (regcache);
+ aspace = get_regcache_aspace (regcache);
pc = regcache_read_pc (regcache);
if (step > 0)
if (addr == (CORE_ADDR) -1)
{
- if (pc == stop_pc && breakpoint_here_p (pc)
+ if (pc == stop_pc && breakpoint_here_p (aspace, pc)
&& execution_direction != EXEC_REVERSE)
/* There is a breakpoint at the address we will resume at,
step one instruction before inserting breakpoints so that
{
struct regcache *regcache;
struct gdbarch *gdbarch;
+ struct address_space *aspace;
CORE_ADDR breakpoint_pc;
/* If we've hit a breakpoint, we'll normally be stopped with SIGTRAP. If
if (gdbarch_decr_pc_after_break (gdbarch) == 0)
return;
+ aspace = get_regcache_aspace (regcache);
+
/* Find the location where (if we've hit a breakpoint) the
breakpoint would be. */
breakpoint_pc = regcache_read_pc (regcache)
already queued and arrive later. To suppress those spurious
SIGTRAPs, we keep a list of such breakpoint locations for a bit,
and retire them after a number of stop events are reported. */
- if (software_breakpoint_inserted_here_p (breakpoint_pc)
- || (non_stop && moribund_breakpoint_here_p (breakpoint_pc)))
+ if (software_breakpoint_inserted_here_p (aspace, breakpoint_pc)
+ || (non_stop && moribund_breakpoint_here_p (aspace, breakpoint_pc)))
{
struct cleanup *old_cleanups = NULL;
if (RECORD_IS_USED)
fprintf_unfiltered (gdb_stdlog, "infrun: syscall number = '%d'\n",
syscall_number);
- ecs->event_thread->stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid);
+ ecs->event_thread->stop_bpstat
+ = bpstat_stop_status (get_regcache_aspace (regcache),
+ stop_pc, ecs->ptid);
ecs->random_signal = !bpstat_explains_signal (ecs->event_thread->stop_bpstat);
if (!ecs->random_signal)
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_EXITED\n");
inferior_ptid = ecs->ptid;
+ set_current_inferior (find_inferior_pid (ptid_get_pid (ecs->ptid)));
+ set_current_program_space (current_inferior ()->pspace);
+ handle_vfork_child_exec_or_exit (0);
target_terminal_ours (); /* Must do this before mourn anyway */
print_stop_reason (EXITED, ecs->ws.value.integer);
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_SIGNALLED\n");
inferior_ptid = ecs->ptid;
+ set_current_inferior (find_inferior_pid (ptid_get_pid (ecs->ptid)));
+ set_current_program_space (current_inferior ()->pspace);
+ handle_vfork_child_exec_or_exit (0);
stop_print_frame = 0;
target_terminal_ours (); /* Must do this before mourn anyway */
stop_pc = regcache_read_pc (get_thread_regcache (ecs->ptid));
- ecs->event_thread->stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid);
+ ecs->event_thread->stop_bpstat
+ = bpstat_stop_status (get_regcache_aspace (get_current_regcache ()),
+ stop_pc, ecs->ptid);
ecs->random_signal = !bpstat_explains_signal (ecs->event_thread->stop_bpstat);
/* If no catchpoint triggered for this, then keep going. */
if (ecs->random_signal)
{
+ ptid_t parent;
+ ptid_t child;
int should_resume;
+ int follow_child = (follow_fork_mode_string == follow_fork_mode_child);
ecs->event_thread->stop_signal = TARGET_SIGNAL_0;
should_resume = follow_fork ();
+ parent = ecs->ptid;
+ child = ecs->ws.value.related_pid;
+
+ /* In non-stop mode, also resume the other branch. */
+ if (non_stop && !detach_fork)
+ {
+ if (follow_child)
+ switch_to_thread (parent);
+ else
+ switch_to_thread (child);
+
+ ecs->event_thread = inferior_thread ();
+ ecs->ptid = inferior_ptid;
+ keep_going (ecs);
+ }
+
+ if (follow_child)
+ switch_to_thread (child);
+ else
+ switch_to_thread (parent);
+
ecs->event_thread = inferior_thread ();
ecs->ptid = inferior_ptid;
ecs->event_thread->stop_signal = TARGET_SIGNAL_TRAP;
goto process_event_stop_test;
+ case TARGET_WAITKIND_VFORK_DONE:
+ /* Done with the shared memory region. Re-insert breakpoints in
+ the parent, and keep going. */
+
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_VFORK_DONE\n");
+
+ if (!ptid_equal (ecs->ptid, inferior_ptid))
+ context_switch (ecs->ptid);
+
+ current_inferior ()->waiting_for_vfork_done = 0;
+ /* This also takes care of reinserting breakpoints in the
+ previously locked inferior. */
+ keep_going (ecs);
+ return;
+
case TARGET_WAITKIND_EXECD:
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_EXECD\n");
stop_pc = regcache_read_pc (get_thread_regcache (ecs->ptid));
+ /* Do whatever is necessary to the parent branch of the vfork. */
+ handle_vfork_child_exec_or_exit (1);
+
/* This causes the eventpoints and symbol table to be reset.
Must do this now, before trying to determine whether to
stop. */
follow_exec (inferior_ptid, ecs->ws.value.execd_pathname);
- ecs->event_thread->stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid);
+ ecs->event_thread->stop_bpstat
+ = bpstat_stop_status (get_regcache_aspace (get_current_regcache ()),
+ stop_pc, ecs->ptid);
ecs->random_signal = !bpstat_explains_signal (ecs->event_thread->stop_bpstat);
/* Note that this may be referenced from inside
if (ecs->event_thread->stop_signal == TARGET_SIGNAL_TRAP)
{
int thread_hop_needed = 0;
+ struct address_space *aspace = get_regcache_aspace (get_current_regcache ());
/* Check if a regular breakpoint has been hit before checking
for a potential single step breakpoint. Otherwise, GDB will
not see this breakpoint hit when stepping onto breakpoints. */
- if (regular_breakpoint_inserted_here_p (stop_pc))
+ if (regular_breakpoint_inserted_here_p (aspace, stop_pc))
{
ecs->random_signal = 0;
- if (!breakpoint_thread_match (stop_pc, ecs->ptid))
+ if (!breakpoint_thread_match (aspace, stop_pc, ecs->ptid))
thread_hop_needed = 1;
}
else if (singlestep_breakpoints_inserted_p)
non-standard signals can't be explained by the breakpoint. */
if (ecs->event_thread->stop_signal == TARGET_SIGNAL_TRAP
|| (! ecs->event_thread->trap_expected
- && breakpoint_inserted_here_p (stop_pc)
+ && breakpoint_inserted_here_p (get_regcache_aspace (get_current_regcache ()),
+ stop_pc)
&& (ecs->event_thread->stop_signal == TARGET_SIGNAL_ILL
|| ecs->event_thread->stop_signal == TARGET_SIGNAL_SEGV
|| ecs->event_thread->stop_signal == TARGET_SIGNAL_EMT))
}
/* See if there is a breakpoint at the current PC. */
- ecs->event_thread->stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid);
-
+ ecs->event_thread->stop_bpstat
+ = bpstat_stop_status (get_regcache_aspace (get_current_regcache ()),
+ stop_pc, ecs->ptid);
+
/* Following in case break condition called a
function. */
stop_print_frame = 1;
struct symtab_and_line sr_sal;
init_sal (&sr_sal);
sr_sal.pc = pc_after_resolver;
+ sr_sal.pspace = get_frame_program_space (frame);
insert_step_resume_breakpoint_at_sal (gdbarch,
sr_sal, null_frame_id);
/* Normal function call return (static or dynamic). */
init_sal (&sr_sal);
sr_sal.pc = ecs->stop_func_start;
- insert_step_resume_breakpoint_at_sal (gdbarch,
- sr_sal, null_frame_id);
+ sr_sal.pspace = get_frame_program_space (frame);
+ insert_step_resume_breakpoint_at_sal (gdbarch,
+ sr_sal, null_frame_id);
}
else
insert_step_resume_breakpoint_at_caller (frame);
struct symtab_and_line sr_sal;
init_sal (&sr_sal);
sr_sal.pc = ecs->stop_func_start;
+ sr_sal.pspace = get_frame_program_space (frame);
insert_step_resume_breakpoint_at_sal (gdbarch,
sr_sal, null_frame_id);
struct symtab_and_line tmp_sal;
tmp_sal = find_pc_line (ecs->stop_func_start, 0);
+ tmp_sal.pspace = get_frame_program_space (frame);
if (tmp_sal.line != 0)
{
if (execution_direction == EXEC_REVERSE)
struct symtab_and_line sr_sal;
init_sal (&sr_sal);
sr_sal.pc = ecs->stop_func_start;
+ sr_sal.pspace = get_frame_program_space (frame);
insert_step_resume_breakpoint_at_sal (gdbarch,
sr_sal, null_frame_id);
}
struct symtab_and_line sr_sal;
init_sal (&sr_sal);
sr_sal.pc = ecs->stop_func_start;
+ sr_sal.pspace = get_frame_program_space (frame);
insert_step_resume_breakpoint_at_sal (gdbarch,
sr_sal, null_frame_id);
keep_going (ecs);
init_sal (&sr_sal); /* initialize to zeroes */
sr_sal.pc = real_stop_pc;
sr_sal.section = find_pc_overlay (sr_sal.pc);
+ sr_sal.pspace = get_frame_program_space (frame);
/* Do not specify what the fp should be when we stop since
on some machines the prologue is where the new fp value
init_sal (&sr_sal); /* initialize to zeroes */
sr_sal.pc = ecs->stop_func_start;
sr_sal.section = find_pc_overlay (ecs->stop_func_start);
+ sr_sal.pspace = get_frame_program_space (get_current_frame ());
/* Do not specify what the fp should be when we stop since on
some machines the prologue is where the new fp value is
gdbarch = get_frame_arch (return_frame);
sr_sal.pc = gdbarch_addr_bits_remove (gdbarch, get_frame_pc (return_frame));
sr_sal.section = find_pc_overlay (sr_sal.pc);
+ sr_sal.pspace = get_frame_program_space (return_frame);
insert_step_resume_breakpoint_at_sal (gdbarch, sr_sal,
get_stack_frame_id (return_frame));
sr_sal.pc = gdbarch_addr_bits_remove (gdbarch,
frame_unwind_caller_pc (next_frame));
sr_sal.section = find_pc_overlay (sr_sal.pc);
+ sr_sal.pspace = frame_unwind_program_space (next_frame);
insert_step_resume_breakpoint_at_sal (gdbarch, sr_sal,
frame_unwind_caller_id (next_frame));
Delete any breakpoint that is to be deleted at the next stop. */
breakpoint_auto_delete (inferior_thread ()->stop_bpstat);
}
+
+ /* Try to get rid of automatically added inferiors that are no
+ longer needed. Keeping those around slows down things linearly.
+ Note that this never removes the current inferior. */
+ prune_inferiors ();
}
static int
show_follow_fork_mode_string,
&setlist, &showlist);
+ add_setshow_enum_cmd ("follow-exec-mode", class_run,
+ follow_exec_mode_names,
+ &follow_exec_mode_string, _("\
+Set debugger response to a program call of exec."), _("\
+Show debugger response to a program call of exec."), _("\
+An exec call replaces the program image of a process.\n\
+\n\
+follow-exec-mode can be:\n\
+\n\
+ new - the debugger creates a new inferior and rebinds the process \n\
+to this new inferior. The program the process was running before\n\
+the exec call can be restarted afterwards by restarting the original\n\
+inferior.\n\
+\n\
+ same - the debugger keeps the process bound to the same inferior.\n\
+The new executable image replaces the previous executable loaded in\n\
+the inferior. Restarting the inferior after the exec call restarts\n\
+the executable the process was running after the exec call.\n\
+\n\
+By default, the debugger will use the same inferior."),
+ NULL,
+ show_follow_exec_mode_string,
+ &setlist, &showlist);
+
add_setshow_enum_cmd ("scheduler-locking", class_run,
scheduler_enums, &scheduler_mode, _("\
Set mode for locking scheduler during execution."), _("\
set_exec_direction_func, show_exec_direction_func,
&setlist, &showlist);
+ /* Set/show detach-on-fork: user-settable mode. */
+
+ add_setshow_boolean_cmd ("detach-on-fork", class_run, &detach_fork, _("\
+Set whether gdb will detach the child of a fork."), _("\
+Show whether gdb will detach the child of a fork."), _("\
+Tells gdb whether to detach the child of a fork."),
+ NULL, NULL, &setlist, &showlist);
+
/* ptid initializations */
null_ptid = ptid_build (0, 0, 0);
minus_one_ptid = ptid_build (-1, 0, 0);