mirror of
https://github.com/apache/nuttx.git
synced 2026-08-01 20:28:58 +00:00
sched/backtrace: fix cross-CPU buffer access under addrenv
The remote CPU's IPI handler wrote into the caller's buffer directly, which may not be reachable from the target CPU's address environment under CONFIG_ARCH_ADDRENV. Signed-off-by: liang.huang <liang.huang@houmo.ai>
This commit is contained in:
parent
22ff8dbf8f
commit
fd0dd8c597
1 changed files with 93 additions and 4 deletions
|
|
@ -28,15 +28,36 @@
|
|||
#include <nuttx/sched.h>
|
||||
#include <nuttx/init.h>
|
||||
|
||||
#include <sys/param.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "sched.h"
|
||||
|
||||
#ifdef CONFIG_ARCH_HAVE_BACKTRACE
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#if defined(CONFIG_SMP) && defined(CONFIG_ARCH_ADDRENV)
|
||||
|
||||
/* Depth of the scratch buffer used to relay a remote backtrace back to
|
||||
* the caller, since the caller's own buffer may not be mapped in the
|
||||
* address environment active on the target CPU. Requests larger than
|
||||
* this are serviced over multiple round trips.
|
||||
*/
|
||||
|
||||
#define BACKTRACE_SCRATCH_DEPTH 32
|
||||
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
|
||||
struct backtrace_arg_s
|
||||
{
|
||||
pid_t pid;
|
||||
|
|
@ -105,6 +126,11 @@ int sched_backtrace(pid_t tid, FAR void **buffer, int size, int skip)
|
|||
FAR struct tcb_s *tcb = this_task();
|
||||
int ret = 0;
|
||||
|
||||
if (size <= 0 || buffer == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (tcb->pid == tid)
|
||||
{
|
||||
ret = up_backtrace(tcb, buffer, size, skip);
|
||||
|
|
@ -121,25 +147,88 @@ int sched_backtrace(pid_t tid, FAR void **buffer, int size, int skip)
|
|||
tcb->task_state == TSTATE_TASK_RUNNING)
|
||||
{
|
||||
struct backtrace_arg_s arg;
|
||||
bool need_restore;
|
||||
#ifdef CONFIG_ARCH_ADDRENV
|
||||
FAR void *scratch[BACKTRACE_SCRATCH_DEPTH];
|
||||
#endif
|
||||
|
||||
if ((tcb->flags & TCB_FLAG_CPU_LOCKED) != 0)
|
||||
{
|
||||
arg.pid = tcb->pid;
|
||||
arg.need_restore = false;
|
||||
need_restore = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
arg.pid = tcb->pid;
|
||||
arg.need_restore = true;
|
||||
need_restore = true;
|
||||
tcb->flags |= TCB_FLAG_CPU_LOCKED;
|
||||
}
|
||||
|
||||
arg.pid = tcb->pid;
|
||||
|
||||
#ifdef CONFIG_ARCH_ADDRENV
|
||||
arg.buffer = scratch;
|
||||
|
||||
while (ret < size)
|
||||
{
|
||||
arg.size = MIN(size - ret, BACKTRACE_SCRATCH_DEPTH);
|
||||
arg.skip = skip + ret;
|
||||
|
||||
/* If this round's request covers all remaining
|
||||
* frames (i.e. it was not capped by the scratch
|
||||
* buffer), there is nothing left to loop for
|
||||
* afterwards, so it is safe to have it release the
|
||||
* pin as well and skip the data-less round below.
|
||||
*/
|
||||
|
||||
arg.need_restore = need_restore &&
|
||||
arg.size == size - ret;
|
||||
|
||||
if (nxsched_smp_call_single(tcb->cpu,
|
||||
sched_backtrace_handler,
|
||||
&arg) < 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (arg.need_restore)
|
||||
{
|
||||
need_restore = false;
|
||||
}
|
||||
|
||||
memcpy(&buffer[ret], scratch,
|
||||
arg.stacksize * sizeof(FAR void *));
|
||||
ret += arg.stacksize;
|
||||
|
||||
if (arg.stacksize < arg.size)
|
||||
{
|
||||
/* Reached the bottom of the target's stack. */
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* The loop above may have exited without a round
|
||||
* releasing the pin (e.g. it broke out on reaching the
|
||||
* bottom of the stack before a "guaranteed last round"
|
||||
* occurred). Send one more, data-less round purely to
|
||||
* release it.
|
||||
*/
|
||||
|
||||
if (need_restore)
|
||||
{
|
||||
arg.size = 0;
|
||||
arg.need_restore = true;
|
||||
nxsched_smp_call_single(tcb->cpu, sched_backtrace_handler,
|
||||
&arg);
|
||||
}
|
||||
#else
|
||||
arg.need_restore = need_restore;
|
||||
arg.buffer = buffer;
|
||||
arg.size = size;
|
||||
arg.skip = skip;
|
||||
ret = nxsched_smp_call_single(tcb->cpu,
|
||||
sched_backtrace_handler,
|
||||
&arg) < 0 ? 0 : arg.stacksize;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue