gdbserver/linux-low: turn some more static functions into private methods

gdbserver/ChangeLog:
2020-04-02  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>

	Turn some more static methods in linux-low into private methods
	of linux_process_target.

	* linux-low.cc (get_pc): Turn into...
	(linux_process_target::get_pc): ...this.
	(save_stop_reason): Turn into...
	(linux_process_target::save_stop_reason): ...this.
	(thread_still_has_status_pending_p): Turn into...
	(linux_process_target::thread_still_has_status_pending): ...this.
	(status_pending_p_callback): Turn into...
	(linux_process_target::status_pending_p_callback): ...this.
	(resume_stopped_resumed_lwps): Turn into...
	(linux_process_target::resume_stopped_resumed_lwps): ...this.
	(install_software_single_step_breakpoints): Turn into...
	(linux_process_target::install_software_single_step_breakpoints):
	...this.
	(single_step): Turn into...
	(linux_process_target::single_step): ...this.
	(linux_resume_one_lwp_throw): Turn into...
	(linux_process_target::resume_one_lwp_throw): ...this.
	(linux_resume_one_lwp): Turn into...
	(linux_process_target::resume_one_lwp): ...this.
	(resume_status_pending_p): Turn into...
	(linux_process_target::resume_status_pending): ...this.
	(need_step_over_p): Turn into...
	(linux_process_target::thread_needs_step_over): ...this.
	(linux_resume_one_thread): Turn into...
	(linux_process_target::resume_one_thread): ...this.
	(proceed_one_lwp): Turn into...
	(linux_process_target::proceed_one_lwp): ...this.
	(unsuspend_and_proceed_one_lwp): Turn into...
	(linux_process_target::unsuspend_and_proceed_one_lwp): ...this.

	Update the calls/references to the above functions below.

	(linux_process_target::handle_extended_wait)
	(linux_process_target::filter_event)
	(linux_process_target::wait_for_event_filtered)
	(linux_process_target::wait_1)
	(linux_process_target::move_out_of_jump_pad)
	(linux_process_target::start_step_over)
	(linux_process_target::resume)
	(linux_process_target::proceed_all_lwps)
	(regsets_store_inferior_registers)
	(linux_process_target::store_register)

	* linux-low.h (class linux_process_target)
	<get_pc>
	<save_stop_reason>
	<thread_still_has_status_pending>
	<status_pending_p_callback>
	<resume_stopped_resumed_lwps>
	<install_software_single_step_breakpoints>
	<single_step>
	<resume_one_lwp_throw>
	<resume_one_lwp>
	<resume_status_pending>
	<thread_needs_step_over>
	<resume_one_thread>
	<proceed_one_lwp>
	<unsuspend_and_proceed_one_lwp>: Declare.
This commit is contained in:
Tankut Baris Aktemur 2020-04-02 15:11:24 +02:00
parent bd70b1f240
commit df95181f00
3 changed files with 213 additions and 121 deletions

View File

@ -1,3 +1,67 @@
2020-04-02 Tankut Baris Aktemur <tankut.baris.aktemur@intel.com>
Turn some more static methods in linux-low into private methods
of linux_process_target.
* linux-low.cc (get_pc): Turn into...
(linux_process_target::get_pc): ...this.
(save_stop_reason): Turn into...
(linux_process_target::save_stop_reason): ...this.
(thread_still_has_status_pending_p): Turn into...
(linux_process_target::thread_still_has_status_pending): ...this.
(status_pending_p_callback): Turn into...
(linux_process_target::status_pending_p_callback): ...this.
(resume_stopped_resumed_lwps): Turn into...
(linux_process_target::resume_stopped_resumed_lwps): ...this.
(install_software_single_step_breakpoints): Turn into...
(linux_process_target::install_software_single_step_breakpoints):
...this.
(single_step): Turn into...
(linux_process_target::single_step): ...this.
(linux_resume_one_lwp_throw): Turn into...
(linux_process_target::resume_one_lwp_throw): ...this.
(linux_resume_one_lwp): Turn into...
(linux_process_target::resume_one_lwp): ...this.
(resume_status_pending_p): Turn into...
(linux_process_target::resume_status_pending): ...this.
(need_step_over_p): Turn into...
(linux_process_target::thread_needs_step_over): ...this.
(linux_resume_one_thread): Turn into...
(linux_process_target::resume_one_thread): ...this.
(proceed_one_lwp): Turn into...
(linux_process_target::proceed_one_lwp): ...this.
(unsuspend_and_proceed_one_lwp): Turn into...
(linux_process_target::unsuspend_and_proceed_one_lwp): ...this.
Update the calls/references to the above functions below.
(linux_process_target::handle_extended_wait)
(linux_process_target::filter_event)
(linux_process_target::wait_for_event_filtered)
(linux_process_target::wait_1)
(linux_process_target::move_out_of_jump_pad)
(linux_process_target::start_step_over)
(linux_process_target::resume)
(linux_process_target::proceed_all_lwps)
(regsets_store_inferior_registers)
(linux_process_target::store_register)
* linux-low.h (class linux_process_target)
<get_pc>
<save_stop_reason>
<thread_still_has_status_pending>
<status_pending_p_callback>
<resume_stopped_resumed_lwps>
<install_software_single_step_breakpoints>
<single_step>
<resume_one_lwp_throw>
<resume_one_lwp>
<resume_status_pending>
<thread_needs_step_over>
<resume_one_thread>
<proceed_one_lwp>
<unsuspend_and_proceed_one_lwp>: Declare.
2020-04-02 Tankut Baris Aktemur <tankut.baris.aktemur@intel.com>
Turn the 'fetch_register' linux target op into a method of

View File

@ -267,8 +267,6 @@ int using_threads = 1;
jump pads). */
static int stabilizing_threads;
static void linux_resume_one_lwp (struct lwp_info *lwp,
int step, int signal, siginfo_t *info);
static void unsuspend_all_lwps (struct lwp_info *except);
static struct lwp_info *add_lwp (ptid_t ptid);
static void mark_lwp_dead (struct lwp_info *lwp, int wstat);
@ -278,7 +276,6 @@ static int kill_lwp (unsigned long lwpid, int signo);
static void enqueue_pending_signal (struct lwp_info *lwp, int signal, siginfo_t *info);
static int linux_low_ptrace_options (int attached);
static int check_ptrace_stopped_lwp_gone (struct lwp_info *lp);
static void proceed_one_lwp (thread_info *thread, lwp_info *except);
/* When the event-loop is doing a step-over, this points at the thread
being stepped. */
@ -438,8 +435,6 @@ linux_add_process (int pid, int attached)
return proc;
}
static CORE_ADDR get_pc (struct lwp_info *lwp);
void
linux_process_target::arch_setup_thread (thread_info *thread)
{
@ -616,9 +611,9 @@ linux_process_target::handle_extended_wait (lwp_info **orig_event_lwp,
new_lwp = add_lwp (ptid);
/* Either we're going to immediately resume the new thread
or leave it stopped. linux_resume_one_lwp is a nop if it
or leave it stopped. resume_one_lwp is a nop if it
thinks the thread is currently running, so set this first
before calling linux_resume_one_lwp. */
before calling resume_one_lwp. */
new_lwp->stopped = 1;
/* If we're suspending all threads, leave this one suspended
@ -726,11 +721,8 @@ linux_process_target::handle_extended_wait (lwp_info **orig_event_lwp,
internal_error (__FILE__, __LINE__, _("unknown ptrace event %d"), event);
}
/* Return the PC as read from the regcache of LWP, without any
adjustment. */
static CORE_ADDR
get_pc (struct lwp_info *lwp)
CORE_ADDR
linux_process_target::get_pc (lwp_info *lwp)
{
struct thread_info *saved_thread;
struct regcache *regcache;
@ -783,14 +775,8 @@ get_syscall_trapinfo (struct lwp_info *lwp, int *sysno)
static int check_stopped_by_watchpoint (struct lwp_info *child);
/* Called when the LWP stopped for a signal/trap. If it stopped for a
trap check what caused it (breakpoint, watchpoint, trace, etc.),
and save the result in the LWP's stop_reason field. If it stopped
for a breakpoint, decrement the PC if necessary on the lwp's
architecture. Returns true if we now have the LWP's stop PC. */
static int
save_stop_reason (struct lwp_info *lwp)
bool
linux_process_target::save_stop_reason (lwp_info *lwp)
{
CORE_ADDR pc;
CORE_ADDR sw_breakpoint_pc;
@ -800,7 +786,7 @@ save_stop_reason (struct lwp_info *lwp)
#endif
if (the_low_target.get_pc == NULL)
return 0;
return false;
pc = get_pc (lwp);
sw_breakpoint_pc = pc - the_low_target.decr_pc_after_break;
@ -921,7 +907,7 @@ save_stop_reason (struct lwp_info *lwp)
lwp->stop_pc = pc;
current_thread = saved_thread;
return 1;
return true;
}
static struct lwp_info *
@ -1678,12 +1664,8 @@ linux_process_target::thread_alive (ptid_t ptid)
return 0;
}
/* Return 1 if this lwp still has an interesting status pending. If
not (e.g., it had stopped for a breakpoint that is gone), return
false. */
static int
thread_still_has_status_pending_p (struct thread_info *thread)
bool
linux_process_target::thread_still_has_status_pending (thread_info *thread)
{
struct lwp_info *lp = get_thread_lwp (thread);
@ -1766,9 +1748,9 @@ lwp_resumed (struct lwp_info *lwp)
return 0;
}
/* Return true if this lwp has an interesting status pending. */
static bool
status_pending_p_callback (thread_info *thread, ptid_t ptid)
bool
linux_process_target::status_pending_p_callback (thread_info *thread,
ptid_t ptid)
{
struct lwp_info *lp = get_thread_lwp (thread);
@ -1781,9 +1763,9 @@ status_pending_p_callback (thread_info *thread, ptid_t ptid)
return 0;
if (lp->status_pending_p
&& !thread_still_has_status_pending_p (thread))
&& !thread_still_has_status_pending (thread))
{
linux_resume_one_lwp (lp, lp->stepping, GDB_SIGNAL_0, NULL);
resume_one_lwp (lp, lp->stepping, GDB_SIGNAL_0, NULL);
return 0;
}
@ -2517,7 +2499,7 @@ linux_process_target::filter_event (int lwpid, int wstat)
child->stepping ? "step" : "continue",
target_pid_to_str (ptid_of (thread)));
linux_resume_one_lwp (child, child->stepping, 0, NULL);
resume_one_lwp (child, child->stepping, 0, NULL);
return NULL;
}
}
@ -2543,11 +2525,8 @@ maybe_hw_step (struct thread_info *thread)
}
}
/* Resume LWPs that are currently stopped without any pending status
to report, but are resumed from the core's perspective. */
static void
resume_stopped_resumed_lwps (thread_info *thread)
void
linux_process_target::resume_stopped_resumed_lwps (thread_info *thread)
{
struct lwp_info *lp = get_thread_lwp (thread);
@ -2567,7 +2546,7 @@ resume_stopped_resumed_lwps (thread_info *thread)
paddress (lp->stop_pc),
step);
linux_resume_one_lwp (lp, step, GDB_SIGNAL_0, NULL);
resume_one_lwp (lp, step, GDB_SIGNAL_0, NULL);
}
}
@ -2614,7 +2593,7 @@ linux_process_target::wait_for_event_filtered (ptid_t wait_ptid,
&requested_child->status_pending);
requested_child->status_pending_p = 0;
requested_child->status_pending = 0;
linux_resume_one_lwp (requested_child, 0, 0, NULL);
resume_one_lwp (requested_child, 0, 0, NULL);
}
if (requested_child->suspended
@ -2702,7 +2681,10 @@ linux_process_target::wait_for_event_filtered (ptid_t wait_ptid,
/* Now that we've pulled all events out of the kernel, resume
LWPs that don't have an interesting event to report. */
if (stopping_threads == NOT_STOPPING_THREADS)
for_each_thread (resume_stopped_resumed_lwps);
for_each_thread ([this] (thread_info *thread)
{
resume_stopped_resumed_lwps (thread);
});
/* ... and find an LWP with a status to report to the core, if
any. */
@ -3272,7 +3254,7 @@ linux_process_target::wait_1 (ptid_t ptid, target_waitstatus *ourstatus,
debug_printf ("Signal %d for LWP %ld deferred (in jump pad)\n",
WSTOPSIG (w), lwpid_of (current_thread));
linux_resume_one_lwp (event_child, 0, 0, NULL);
resume_one_lwp (event_child, 0, 0, NULL);
if (debug_threads)
debug_exit ();
@ -3372,8 +3354,7 @@ linux_process_target::wait_1 (ptid_t ptid, target_waitstatus *ourstatus,
lwpid_of (current_thread));
}
linux_resume_one_lwp (event_child, event_child->stepping,
0, NULL);
resume_one_lwp (event_child, event_child->stepping, 0, NULL);
if (debug_threads)
debug_exit ();
@ -3429,8 +3410,8 @@ linux_process_target::wait_1 (ptid_t ptid, target_waitstatus *ourstatus,
}
else
{
linux_resume_one_lwp (event_child, event_child->stepping,
WSTOPSIG (w), info_p);
resume_one_lwp (event_child, event_child->stepping,
WSTOPSIG (w), info_p);
}
if (debug_threads)
@ -4039,7 +4020,7 @@ linux_process_target::move_out_of_jump_pad (thread_info *thread)
WSTOPSIG (*wstat), lwpid_of (thread));
}
linux_resume_one_lwp (lwp, 0, 0, NULL);
resume_one_lwp (lwp, 0, 0, NULL);
}
else
lwp_suspended_inc (lwp);
@ -4117,10 +4098,8 @@ enqueue_pending_signal (struct lwp_info *lwp, int signal, siginfo_t *info)
lwp->pending_signals = p_sig;
}
/* Install breakpoints for software single stepping. */
static void
install_software_single_step_breakpoints (struct lwp_info *lwp)
void
linux_process_target::install_software_single_step_breakpoints (lwp_info *lwp)
{
struct thread_info *thread = get_lwp_thread (lwp);
struct regcache *regcache = get_thread_regcache (thread, 1);
@ -4134,12 +4113,8 @@ install_software_single_step_breakpoints (struct lwp_info *lwp)
set_single_step_breakpoint (pc, current_ptid);
}
/* Single step via hardware or software single step.
Return 1 if hardware single stepping, 0 if software single stepping
or can't single step. */
static int
single_step (struct lwp_info* lwp)
int
linux_process_target::single_step (lwp_info* lwp)
{
int step = 0;
@ -4174,12 +4149,9 @@ lwp_signal_can_be_delivered (struct lwp_info *lwp)
== fast_tpoint_collect_result::not_collecting);
}
/* Resume execution of LWP. If STEP is nonzero, single-step it. If
SIGNAL is nonzero, give it that signal. */
static void
linux_resume_one_lwp_throw (struct lwp_info *lwp,
int step, int signal, siginfo_t *info)
void
linux_process_target::resume_one_lwp_throw (lwp_info *lwp, int step,
int signal, siginfo_t *info)
{
struct thread_info *thread = get_lwp_thread (lwp);
struct thread_info *saved_thread;
@ -4416,16 +4388,13 @@ check_ptrace_stopped_lwp_gone (struct lwp_info *lp)
return 0;
}
/* Like linux_resume_one_lwp_throw, but no error is thrown if the LWP
disappears while we try to resume it. */
static void
linux_resume_one_lwp (struct lwp_info *lwp,
int step, int signal, siginfo_t *info)
void
linux_process_target::resume_one_lwp (lwp_info *lwp, int step, int signal,
siginfo_t *info)
{
try
{
linux_resume_one_lwp_throw (lwp, step, signal, info);
resume_one_lwp_throw (lwp, step, signal, info);
}
catch (const gdb_exception_error &ex)
{
@ -4546,11 +4515,8 @@ linux_set_resume_request (thread_info *thread, thread_resume *resume, size_t n)
lwp->resume = NULL;
}
/* find_thread callback for linux_resume. Return true if this lwp has an
interesting status pending. */
static bool
resume_status_pending_p (thread_info *thread)
bool
linux_process_target::resume_status_pending (thread_info *thread)
{
struct lwp_info *lwp = get_thread_lwp (thread);
@ -4559,16 +4525,11 @@ resume_status_pending_p (thread_info *thread)
if (lwp->resume == NULL)
return false;
return thread_still_has_status_pending_p (thread);
return thread_still_has_status_pending (thread);
}
/* Return 1 if this lwp that GDB wants running is stopped at an
internal breakpoint that we need to step over. It assumes that any
required STOP_PC adjustment has already been propagated to the
inferior's regcache. */
static bool
need_step_over_p (thread_info *thread)
bool
linux_process_target::thread_needs_step_over (thread_info *thread)
{
struct lwp_info *lwp = get_thread_lwp (thread);
struct thread_info *saved_thread;
@ -4739,7 +4700,7 @@ linux_process_target::start_step_over (lwp_info *lwp)
current_thread = saved_thread;
linux_resume_one_lwp (lwp, step, 0, NULL);
resume_one_lwp (lwp, step, 0, NULL);
/* Require next event from this LWP. */
step_over_bkpt = thread->id;
@ -4814,21 +4775,9 @@ linux_process_target::complete_ongoing_step_over ()
}
}
/* This function is called once per thread. We check the thread's resume
request, which will tell us whether to resume, step, or leave the thread
stopped; and what signal, if any, it should be sent.
For threads which we aren't explicitly told otherwise, we preserve
the stepping flag; this is used for stepping over gdbserver-placed
breakpoints.
If pending_flags was set in any thread, we queue any needed
signals, since we won't actually resume. We already have a pending
event to report, so we don't need to preserve any step requests;
they should be re-issued if necessary. */
static void
linux_resume_one_thread (thread_info *thread, bool leave_all_stopped)
void
linux_process_target::resume_one_thread (thread_info *thread,
bool leave_all_stopped)
{
struct lwp_info *lwp = get_thread_lwp (thread);
int leave_pending;
@ -4955,7 +4904,10 @@ linux_process_target::resume (thread_resume *resume_info, size_t n)
before considering to start a step-over (in all-stop). */
bool any_pending = false;
if (!non_stop)
any_pending = find_thread (resume_status_pending_p) != NULL;
any_pending = find_thread ([this] (thread_info *thread)
{
return resume_status_pending (thread);
}) != nullptr;
/* If there is a thread which would otherwise be resumed, which is
stopped at a breakpoint that needs stepping over, then don't
@ -4964,7 +4916,10 @@ linux_process_target::resume (thread_resume *resume_info, size_t n)
to queue any signals that would otherwise be delivered or
queued. */
if (!any_pending && supports_breakpoints ())
need_step_over = find_thread (need_step_over_p);
need_step_over = find_thread ([this] (thread_info *thread)
{
return thread_needs_step_over (thread);
});
bool leave_all_stopped = (need_step_over != NULL || any_pending);
@ -4983,7 +4938,7 @@ linux_process_target::resume (thread_resume *resume_info, size_t n)
otherwise deliver. */
for_each_thread ([&] (thread_info *thread)
{
linux_resume_one_thread (thread, leave_all_stopped);
resume_one_thread (thread, leave_all_stopped);
});
if (need_step_over)
@ -5001,17 +4956,8 @@ linux_process_target::resume (thread_resume *resume_info, size_t n)
async_file_mark ();
}
/* This function is called once per thread. We check the thread's
last resume request, which will tell us whether to resume, step, or
leave the thread stopped. Any signal the client requested to be
delivered has already been enqueued at this point.
If any thread that GDB wants running is stopped at an internal
breakpoint that needs stepping over, we start a step-over operation
on that particular thread, and leave all others stopped. */
static void
proceed_one_lwp (thread_info *thread, lwp_info *except)
void
linux_process_target::proceed_one_lwp (thread_info *thread, lwp_info *except)
{
struct lwp_info *lwp = get_thread_lwp (thread);
int step;
@ -5104,11 +5050,12 @@ proceed_one_lwp (thread_info *thread, lwp_info *except)
else
step = 0;
linux_resume_one_lwp (lwp, step, 0, NULL);
resume_one_lwp (lwp, step, 0, NULL);
}
static void
unsuspend_and_proceed_one_lwp (thread_info *thread, lwp_info *except)
void
linux_process_target::unsuspend_and_proceed_one_lwp (thread_info *thread,
lwp_info *except)
{
struct lwp_info *lwp = get_thread_lwp (thread);
@ -5132,7 +5079,10 @@ linux_process_target::proceed_all_lwps ()
if (supports_breakpoints ())
{
need_step_over = find_thread (need_step_over_p);
need_step_over = find_thread ([this] (thread_info *thread)
{
return thread_needs_step_over (thread);
});
if (need_step_over != NULL)
{
@ -5149,7 +5099,7 @@ linux_process_target::proceed_all_lwps ()
if (debug_threads)
debug_printf ("Proceeding, no step-over needed\n");
for_each_thread ([] (thread_info *thread)
for_each_thread ([this] (thread_info *thread)
{
proceed_one_lwp (thread, NULL);
});
@ -5362,7 +5312,7 @@ regsets_store_inferior_registers (struct regsets_info *regsets_info,
/* At this point, ESRCH should mean the process is
already gone, in which case we simply ignore attempts
to change its registers. See also the related
comment in linux_resume_one_lwp. */
comment in resume_one_lwp. */
free (buf);
return 0;
}
@ -5509,7 +5459,7 @@ linux_process_target::store_register (const usrregs_info *usrregs,
/* At this point, ESRCH should mean the process is
already gone, in which case we simply ignore attempts
to change its registers. See also the related
comment in linux_resume_one_lwp. */
comment in resume_one_lwp. */
if (errno == ESRCH)
return;

View File

@ -580,6 +580,84 @@ private:
void usr_store_inferior_registers (const regs_info *regs_info,
regcache *regcache, int regno, int all);
/* Return the PC as read from the regcache of LWP, without any
adjustment. */
CORE_ADDR get_pc (lwp_info *lwp);
/* Called when the LWP stopped for a signal/trap. If it stopped for a
trap check what caused it (breakpoint, watchpoint, trace, etc.),
and save the result in the LWP's stop_reason field. If it stopped
for a breakpoint, decrement the PC if necessary on the lwp's
architecture. Returns true if we now have the LWP's stop PC. */
bool save_stop_reason (lwp_info *lwp);
/* Resume execution of LWP. If STEP is nonzero, single-step it. If
SIGNAL is nonzero, give it that signal. */
void resume_one_lwp_throw (lwp_info *lwp, int step, int signal,
siginfo_t *info);
/* Like resume_one_lwp_throw, but no error is thrown if the LWP
disappears while we try to resume it. */
void resume_one_lwp (lwp_info *lwp, int step, int signal, siginfo_t *info);
/* This function is called once per thread. We check the thread's
last resume request, which will tell us whether to resume, step, or
leave the thread stopped. Any signal the client requested to be
delivered has already been enqueued at this point.
If any thread that GDB wants running is stopped at an internal
breakpoint that needs stepping over, we start a step-over operation
on that particular thread, and leave all others stopped. */
void proceed_one_lwp (thread_info *thread, lwp_info *except);
/* This function is called once per thread. We check the thread's
resume request, which will tell us whether to resume, step, or
leave the thread stopped; and what signal, if any, it should be
sent.
For threads which we aren't explicitly told otherwise, we preserve
the stepping flag; this is used for stepping over gdbserver-placed
breakpoints.
If pending_flags was set in any thread, we queue any needed
signals, since we won't actually resume. We already have a pending
event to report, so we don't need to preserve any step requests;
they should be re-issued if necessary. */
void resume_one_thread (thread_info *thread, bool leave_all_stopped);
/* Return true if this lwp has an interesting status pending. */
bool status_pending_p_callback (thread_info *thread, ptid_t ptid);
/* Resume LWPs that are currently stopped without any pending status
to report, but are resumed from the core's perspective. */
void resume_stopped_resumed_lwps (thread_info *thread);
/* Unsuspend THREAD, except EXCEPT, and proceed. */
void unsuspend_and_proceed_one_lwp (thread_info *thread, lwp_info *except);
/* Return true if this lwp still has an interesting status pending.
If not (e.g., it had stopped for a breakpoint that is gone), return
false. */
bool thread_still_has_status_pending (thread_info *thread);
/* Return true if this lwp is to-be-resumed and has an interesting
status pending. */
bool resume_status_pending (thread_info *thread);
/* Return true if this lwp that GDB wants running is stopped at an
internal breakpoint that we need to step over. It assumes that
any required STOP_PC adjustment has already been propagated to
the inferior's regcache. */
bool thread_needs_step_over (thread_info *thread);
/* Single step via hardware or software single step.
Return 1 if hardware single stepping, 0 if software single stepping
or can't single step. */
int single_step (lwp_info* lwp);
/* Install breakpoints for software single stepping. */
void install_software_single_step_breakpoints (lwp_info *lwp);
protected:
/* The architecture-specific "low" methods are listed below. */