e5cf86267b
This patch fixup the script execution capabilities on argv passing and adds support for arguments larger than 4k. According to POSIX, the script parameter is quiet different from the current implementation. Especially on the way it inserts the path of executables. At the end, when you execute a script from `$PATH`, it always fails. For the script, interpreter will be invoked with the following arguments: `{interpreter [optional-arg] pathname arg...}` where pathname is the pathname of the file specified as the first argument of execve(), and arg... is the series of words pointed to by the argv argument of execve(), starting at argv[1]. Note that there is no way to get the argv[0] that was passed to the execve() call. The changes include: - Separating argument, environment variable, and auxiliary vector processing into a new lwp_args.c file. - Fixing bugs in script argument processing and supporting arguments larger than 4k. - Updating lwp_execve to use the new argscopy function and removing the old lwp_argscopy function. - Making various modifications to lwp_load and elf_aux_fill to work with the new argument processing. - Removing unnecessary code related to dynamic loading and interpreter scripts. Signed-off-by: Shell <smokewood@qq.com>
723 lines
17 KiB
C
723 lines
17 KiB
C
/*
|
|
* Copyright (c) 2006-2021, RT-Thread Development Team
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* Change Logs:
|
|
* Date Author Notes
|
|
* 2006-03-12 Bernard first version
|
|
* 2018-11-02 heyuanjie fix complie error in iar
|
|
* 2021-02-03 lizhirui add 64-bit arch support and riscv64 arch support
|
|
* 2021-08-26 linzhenxing add lwp_setcwd\lwp_getcwd
|
|
* 2023-02-20 wangxiaoyao inv icache before new app startup
|
|
* 2023-02-20 wangxiaoyao fix bug on foreground app switch
|
|
* 2023-10-16 Shell Support a new backtrace framework
|
|
* 2023-11-17 xqyjlj add process group and session support
|
|
* 2023-11-30 Shell add lwp_startup()
|
|
*/
|
|
|
|
#define DBG_TAG "lwp"
|
|
#define DBG_LVL DBG_INFO
|
|
#include <rtdbg.h>
|
|
|
|
#include <rthw.h>
|
|
#include <rtthread.h>
|
|
|
|
#include <dfs_file.h>
|
|
#include <unistd.h>
|
|
#include <stdio.h> /* rename() */
|
|
#include <fcntl.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/statfs.h> /* statfs() */
|
|
|
|
#include <lwp_elf.h>
|
|
|
|
#ifndef RT_USING_DFS
|
|
#error "lwp need file system(RT_USING_DFS)"
|
|
#endif
|
|
|
|
#include "lwp_internal.h"
|
|
#include "lwp_arch.h"
|
|
#include "lwp_arch_comm.h"
|
|
#include "lwp_signal.h"
|
|
#include "lwp_dbg.h"
|
|
#include <terminal/terminal.h>
|
|
|
|
#ifdef ARCH_MM_MMU
|
|
#include <lwp_user_mm.h>
|
|
#endif /* end of ARCH_MM_MMU */
|
|
|
|
|
|
#ifndef O_DIRECTORY
|
|
#define O_DIRECTORY 0x200000
|
|
#endif
|
|
|
|
#ifndef O_BINARY
|
|
#define O_BINARY 0x10000
|
|
#endif
|
|
|
|
#ifdef DFS_USING_WORKDIR
|
|
extern char working_directory[];
|
|
#endif
|
|
|
|
static int lwp_component_init(void)
|
|
{
|
|
int rc;
|
|
if ((rc = lwp_tid_init()) != RT_EOK)
|
|
{
|
|
LOG_E("%s: lwp_component_init() failed", __func__);
|
|
}
|
|
else if ((rc = lwp_pid_init()) != RT_EOK)
|
|
{
|
|
LOG_E("%s: lwp_pid_init() failed", __func__);
|
|
}
|
|
else if ((rc = rt_channel_component_init()) != RT_EOK)
|
|
{
|
|
LOG_E("%s: rt_channel_component_init failed", __func__);
|
|
}
|
|
else if ((rc = lwp_futex_init()) != RT_EOK)
|
|
{
|
|
LOG_E("%s: lwp_futex_init() failed", __func__);
|
|
}
|
|
return rc;
|
|
}
|
|
INIT_COMPONENT_EXPORT(lwp_component_init);
|
|
|
|
rt_weak int lwp_startup_debug_request(void)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
#define LATENCY_TIMES (3)
|
|
#define LATENCY_IN_MSEC (128)
|
|
#define LWP_CONSOLE_PATH "CONSOLE=/dev/console"
|
|
const char *init_search_path[] = {
|
|
"/sbin/init",
|
|
"/bin/init",
|
|
};
|
|
|
|
/**
|
|
* Startup process 0 and do the essential works
|
|
* This is the "Hello World" point of RT-Smart
|
|
*/
|
|
static int lwp_startup(void)
|
|
{
|
|
int error;
|
|
|
|
const char *init_path;
|
|
char *argv[] = {0, "&"};
|
|
char *envp[] = {LWP_CONSOLE_PATH, 0};
|
|
|
|
#ifdef LWP_DEBUG_INIT
|
|
int command;
|
|
int countdown = LATENCY_TIMES;
|
|
while (countdown)
|
|
{
|
|
command = lwp_startup_debug_request();
|
|
if (command)
|
|
{
|
|
return 0;
|
|
}
|
|
rt_kprintf("Press any key to stop init process startup ... %d\n", countdown);
|
|
countdown -= 1;
|
|
rt_thread_mdelay(LATENCY_IN_MSEC);
|
|
}
|
|
rt_kprintf("Starting init ...\n");
|
|
#endif /* LWP_DEBUG_INIT */
|
|
|
|
for (size_t i = 0; i < sizeof(init_search_path)/sizeof(init_search_path[0]); i++)
|
|
{
|
|
struct stat s;
|
|
init_path = init_search_path[i];
|
|
error = stat(init_path, &s);
|
|
if (error == 0)
|
|
{
|
|
argv[0] = (void *)init_path;
|
|
error = lwp_execve((void *)init_path, 0, sizeof(argv)/sizeof(argv[0]), argv, envp);
|
|
if (error < 0)
|
|
{
|
|
LOG_E("%s: failed to startup process 0 (init)\n"
|
|
"Switching to legacy mode...", __func__);
|
|
}
|
|
else if (error != 1)
|
|
{
|
|
LOG_E("%s: pid 1 is already allocated", __func__);
|
|
error = -EBUSY;
|
|
}
|
|
else
|
|
{
|
|
rt_lwp_t p = lwp_from_pid_locked(1);
|
|
p->sig_protected = 1;
|
|
|
|
error = 0;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (error)
|
|
{
|
|
LOG_D("%s: init program not found\n"
|
|
"Switching to legacy mode...", __func__);
|
|
}
|
|
return error;
|
|
}
|
|
INIT_APP_EXPORT(lwp_startup);
|
|
|
|
void lwp_setcwd(char *buf)
|
|
{
|
|
struct rt_lwp *lwp = RT_NULL;
|
|
|
|
if(strlen(buf) >= DFS_PATH_MAX)
|
|
{
|
|
rt_kprintf("buf too long!\n");
|
|
return ;
|
|
}
|
|
|
|
lwp = (struct rt_lwp *)rt_thread_self()->lwp;
|
|
if (lwp)
|
|
{
|
|
rt_strncpy(lwp->working_directory, buf, DFS_PATH_MAX - 1);
|
|
}
|
|
else
|
|
{
|
|
rt_strncpy(working_directory, buf, DFS_PATH_MAX - 1);
|
|
}
|
|
|
|
return ;
|
|
}
|
|
|
|
char *lwp_getcwd(void)
|
|
{
|
|
char *dir_buf = RT_NULL;
|
|
struct rt_lwp *lwp = RT_NULL;
|
|
rt_thread_t thread = rt_thread_self();
|
|
|
|
if (thread)
|
|
{
|
|
lwp = (struct rt_lwp *)thread->lwp;
|
|
}
|
|
|
|
if (lwp)
|
|
{
|
|
if(lwp->working_directory[0] != '/')
|
|
{
|
|
dir_buf = &working_directory[0];
|
|
}
|
|
else
|
|
{
|
|
dir_buf = &lwp->working_directory[0];
|
|
}
|
|
}
|
|
else
|
|
dir_buf = &working_directory[0];
|
|
|
|
return dir_buf;
|
|
}
|
|
|
|
/**
|
|
* RT-Thread light-weight process
|
|
*/
|
|
void lwp_set_kernel_sp(uint32_t *sp)
|
|
{
|
|
rt_thread_self()->kernel_sp = (rt_uint32_t *)sp;
|
|
}
|
|
|
|
uint32_t *lwp_get_kernel_sp(void)
|
|
{
|
|
#ifdef ARCH_MM_MMU
|
|
return (uint32_t *)rt_thread_self()->sp;
|
|
#else
|
|
uint32_t* kernel_sp;
|
|
extern rt_uint32_t rt_interrupt_from_thread;
|
|
extern rt_uint32_t rt_thread_switch_interrupt_flag;
|
|
if (rt_thread_switch_interrupt_flag)
|
|
{
|
|
kernel_sp = (uint32_t *)((rt_thread_t)rt_container_of(rt_interrupt_from_thread, struct rt_thread, sp))->kernel_sp;
|
|
}
|
|
else
|
|
{
|
|
kernel_sp = (uint32_t *)rt_thread_self()->kernel_sp;
|
|
}
|
|
return kernel_sp;
|
|
#endif
|
|
}
|
|
|
|
|
|
/* lwp-thread clean up routine */
|
|
void lwp_cleanup(struct rt_thread *tid)
|
|
{
|
|
struct rt_lwp *lwp;
|
|
|
|
if (tid == NULL)
|
|
{
|
|
LOG_I("%s: invalid parameter tid == NULL", __func__);
|
|
return;
|
|
}
|
|
else
|
|
LOG_D("cleanup thread: %s, stack_addr: 0x%x", tid->parent.name, tid->stack_addr);
|
|
|
|
/**
|
|
* Brief: lwp thread cleanup
|
|
*
|
|
* Note: Critical Section
|
|
* - thread control block (RW. It's ensured that no one else can access tcb
|
|
* other than itself)
|
|
*/
|
|
lwp = (struct rt_lwp *)tid->lwp;
|
|
lwp_thread_signal_detach(&tid->signal);
|
|
|
|
/* tty will be release in lwp_ref_dec() if ref is cleared */
|
|
lwp_ref_dec(lwp);
|
|
return;
|
|
}
|
|
|
|
static void lwp_execve_setup_stdio(struct rt_lwp *lwp)
|
|
{
|
|
struct dfs_fdtable *lwp_fdt;
|
|
struct dfs_file *cons_file;
|
|
int cons_fd;
|
|
|
|
lwp_fdt = &lwp->fdt;
|
|
|
|
/* open console */
|
|
cons_fd = open("/dev/console", O_RDWR);
|
|
if (cons_fd < 0)
|
|
{
|
|
LOG_E("%s: Cannot open console tty", __func__);
|
|
return ;
|
|
}
|
|
LOG_D("%s: open console as fd %d", __func__, cons_fd);
|
|
|
|
/* init 4 fds */
|
|
lwp_fdt->fds = rt_calloc(4, sizeof(void *));
|
|
if (lwp_fdt->fds)
|
|
{
|
|
cons_file = fd_get(cons_fd);
|
|
lwp_fdt->maxfd = 4;
|
|
fdt_fd_associate_file(lwp_fdt, 0, cons_file);
|
|
fdt_fd_associate_file(lwp_fdt, 1, cons_file);
|
|
fdt_fd_associate_file(lwp_fdt, 2, cons_file);
|
|
}
|
|
|
|
close(cons_fd);
|
|
return;
|
|
}
|
|
|
|
static void _lwp_thread_entry(void *parameter)
|
|
{
|
|
rt_thread_t tid;
|
|
struct rt_lwp *lwp;
|
|
|
|
tid = rt_thread_self();
|
|
lwp = (struct rt_lwp *)tid->lwp;
|
|
tid->cleanup = lwp_cleanup;
|
|
tid->user_stack = RT_NULL;
|
|
|
|
if (lwp->debug)
|
|
{
|
|
lwp->bak_first_inst = *(uint32_t *)lwp->text_entry;
|
|
*(uint32_t *)lwp->text_entry = dbg_get_ins();
|
|
rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, lwp->text_entry, sizeof(uint32_t));
|
|
icache_invalid_all();
|
|
}
|
|
|
|
/**
|
|
* without ASID support, it will be a special case when trying to run application
|
|
* and exit multiple times and a same page frame allocated to it bound to
|
|
* different text segment. Then we are in a situation where icache contains
|
|
* out-of-dated data and must be handle by the running core itself.
|
|
* with ASID support, this should be a rare case that ASID & page frame both
|
|
* identical to previous running application.
|
|
*
|
|
* For a new application loaded into memory, icache are seen as empty. And there
|
|
* should be nothing in the icache entry to match. So this icache invalidation
|
|
* operation should have barely influence.
|
|
*/
|
|
rt_hw_icache_invalidate_all();
|
|
|
|
#ifdef ARCH_MM_MMU
|
|
arch_start_umode(lwp->args, lwp->text_entry, (void *)USER_STACK_VEND, (char *)tid->stack_addr + tid->stack_size);
|
|
#else
|
|
arch_start_umode(lwp->args, lwp->text_entry, lwp->data_entry, (void *)((uint32_t)lwp->data_entry + lwp->data_size));
|
|
#endif /* ARCH_MM_MMU */
|
|
}
|
|
|
|
struct rt_lwp *lwp_self(void)
|
|
{
|
|
rt_thread_t tid;
|
|
|
|
tid = rt_thread_self();
|
|
if (tid)
|
|
{
|
|
return (struct rt_lwp *)tid->lwp;
|
|
}
|
|
|
|
return RT_NULL;
|
|
}
|
|
|
|
rt_err_t lwp_children_register(struct rt_lwp *parent, struct rt_lwp *child)
|
|
{
|
|
/* lwp add to children link */
|
|
LWP_LOCK(parent);
|
|
child->sibling = parent->first_child;
|
|
parent->first_child = child;
|
|
child->parent = parent;
|
|
LWP_UNLOCK(parent);
|
|
|
|
LOG_D("%s(parent=%p, child=%p)", __func__, parent, child);
|
|
/* parent holds reference to child */
|
|
lwp_ref_inc(parent);
|
|
/* child holds reference to parent */
|
|
lwp_ref_inc(child);
|
|
|
|
return 0;
|
|
}
|
|
|
|
rt_err_t lwp_children_unregister(struct rt_lwp *parent, struct rt_lwp *child)
|
|
{
|
|
struct rt_lwp **lwp_node;
|
|
|
|
LWP_LOCK(parent);
|
|
/* detach from children link */
|
|
lwp_node = &parent->first_child;
|
|
while (*lwp_node != child)
|
|
{
|
|
RT_ASSERT(*lwp_node != RT_NULL);
|
|
lwp_node = &(*lwp_node)->sibling;
|
|
}
|
|
(*lwp_node) = child->sibling;
|
|
child->parent = RT_NULL;
|
|
LWP_UNLOCK(parent);
|
|
|
|
LOG_D("%s(parent=%p, child=%p)", __func__, parent, child);
|
|
lwp_ref_dec(child);
|
|
lwp_ref_dec(parent);
|
|
|
|
return 0;
|
|
}
|
|
|
|
struct process_aux *argscopy(struct rt_lwp *lwp, int argc, char **argv, char **envp)
|
|
{
|
|
struct lwp_args_info ai;
|
|
rt_err_t error;
|
|
struct process_aux *ua;
|
|
const char **tail_argv[2] = {0};
|
|
|
|
error = lwp_args_init(&ai);
|
|
if (error)
|
|
{
|
|
return RT_NULL;
|
|
}
|
|
|
|
if (argc > 0)
|
|
{
|
|
tail_argv[0] = (void *)argv[argc - 1];
|
|
argv[argc - 1] = NULL;
|
|
lwp_args_put(&ai, (void *)argv, LWP_ARGS_TYPE_KARG);
|
|
lwp_args_put(&ai, (void *)tail_argv, LWP_ARGS_TYPE_KARG);
|
|
}
|
|
lwp_args_put(&ai, (void *)envp, LWP_ARGS_TYPE_KENVP);
|
|
|
|
ua = lwp_argscopy(lwp, &ai);
|
|
lwp_args_detach(&ai);
|
|
|
|
return ua;
|
|
}
|
|
|
|
pid_t lwp_execve(char *filename, int debug, int argc, char **argv, char **envp)
|
|
{
|
|
int result;
|
|
struct rt_lwp *lwp;
|
|
char *thread_name;
|
|
struct process_aux *aux;
|
|
int tid = 0;
|
|
|
|
if (filename == RT_NULL)
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (access(filename, X_OK) != 0)
|
|
{
|
|
return -EACCES;
|
|
}
|
|
|
|
lwp = lwp_create(LWP_CREATE_FLAG_ALLOC_PID | LWP_CREATE_FLAG_NOTRACE_EXEC);
|
|
|
|
if (lwp == RT_NULL)
|
|
{
|
|
dbg_log(DBG_ERROR, "lwp struct out of memory!\n");
|
|
return -ENOMEM;
|
|
}
|
|
LOG_D("lwp malloc : %p, size: %d!", lwp, sizeof(struct rt_lwp));
|
|
|
|
if ((tid = lwp_tid_get()) == 0)
|
|
{
|
|
lwp_ref_dec(lwp);
|
|
return -ENOMEM;
|
|
}
|
|
#ifdef ARCH_MM_MMU
|
|
if (lwp_user_space_init(lwp, 0) != 0)
|
|
{
|
|
lwp_tid_put(tid);
|
|
lwp_ref_dec(lwp);
|
|
return -ENOMEM;
|
|
}
|
|
#endif
|
|
|
|
if ((aux = argscopy(lwp, argc, argv, envp)) == RT_NULL)
|
|
{
|
|
lwp_tid_put(tid);
|
|
lwp_ref_dec(lwp);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
result = lwp_load(filename, lwp, RT_NULL, 0, aux);
|
|
if (result == RT_EOK)
|
|
{
|
|
rt_thread_t thread = RT_NULL;
|
|
rt_uint32_t priority = 25, tick = 200;
|
|
|
|
lwp_execve_setup_stdio(lwp);
|
|
|
|
/* obtain the base name */
|
|
thread_name = strrchr(filename, '/');
|
|
thread_name = thread_name ? thread_name + 1 : filename;
|
|
#ifndef ARCH_MM_MMU
|
|
struct lwp_app_head *app_head = lwp->text_entry;
|
|
if (app_head->priority)
|
|
{
|
|
priority = app_head->priority;
|
|
}
|
|
if (app_head->tick)
|
|
{
|
|
tick = app_head->tick;
|
|
}
|
|
#endif /* not defined ARCH_MM_MMU */
|
|
thread = rt_thread_create(thread_name, _lwp_thread_entry, RT_NULL,
|
|
LWP_TASK_STACK_SIZE, priority, tick);
|
|
if (thread != RT_NULL)
|
|
{
|
|
struct rt_lwp *self_lwp;
|
|
rt_session_t session;
|
|
rt_processgroup_t group;
|
|
|
|
thread->tid = tid;
|
|
lwp_tid_set_thread(tid, thread);
|
|
LOG_D("lwp kernel => (0x%08x, 0x%08x)\n", (rt_size_t)thread->stack_addr,
|
|
(rt_size_t)thread->stack_addr + thread->stack_size);
|
|
self_lwp = lwp_self();
|
|
|
|
/* when create init, self_lwp == null */
|
|
if (self_lwp == RT_NULL && lwp_to_pid(lwp) != 1)
|
|
{
|
|
self_lwp = lwp_from_pid_and_lock(1);
|
|
}
|
|
|
|
if (self_lwp)
|
|
{
|
|
/* lwp add to children link */
|
|
lwp_children_register(self_lwp, lwp);
|
|
}
|
|
|
|
session = RT_NULL;
|
|
group = RT_NULL;
|
|
|
|
group = lwp_pgrp_create(lwp);
|
|
if (group)
|
|
{
|
|
lwp_pgrp_insert(group, lwp);
|
|
if (self_lwp == RT_NULL)
|
|
{
|
|
session = lwp_session_create(lwp);
|
|
lwp_session_insert(session, group);
|
|
}
|
|
else
|
|
{
|
|
session = lwp_session_find(lwp_sid_get_byprocess(self_lwp));
|
|
lwp_session_insert(session, group);
|
|
}
|
|
}
|
|
|
|
thread->lwp = lwp;
|
|
#ifndef ARCH_MM_MMU
|
|
struct lwp_app_head *app_head = (struct lwp_app_head*)lwp->text_entry;
|
|
thread->user_stack = app_head->stack_offset ?
|
|
(void *)(app_head->stack_offset -
|
|
app_head->data_offset +
|
|
(uint32_t)lwp->data_entry) : RT_NULL;
|
|
thread->user_stack_size = app_head->stack_size;
|
|
/* init data area */
|
|
rt_memset(lwp->data_entry, 0, lwp->data_size);
|
|
/* init user stack */
|
|
rt_memset(thread->user_stack, '#', thread->user_stack_size);
|
|
#endif /* not defined ARCH_MM_MMU */
|
|
rt_list_insert_after(&lwp->t_grp, &thread->sibling);
|
|
|
|
lwp->did_exec = RT_TRUE;
|
|
|
|
if (debug && rt_dbg_ops)
|
|
{
|
|
lwp->debug = debug;
|
|
rt_thread_control(thread, RT_THREAD_CTRL_BIND_CPU, (void*)0);
|
|
}
|
|
|
|
rt_thread_startup(thread);
|
|
return lwp_to_pid(lwp);
|
|
}
|
|
}
|
|
|
|
lwp_tid_put(tid);
|
|
lwp_ref_dec(lwp);
|
|
|
|
return -RT_ERROR;
|
|
}
|
|
|
|
#ifdef RT_USING_MUSLLIBC
|
|
extern char **__environ;
|
|
#else
|
|
char **__environ = 0;
|
|
#endif
|
|
|
|
pid_t exec(char *filename, int debug, int argc, char **argv)
|
|
{
|
|
setenv("OS", "RT-Thread", 1);
|
|
return lwp_execve(filename, debug, argc, argv, __environ);
|
|
}
|
|
|
|
#ifdef ARCH_MM_MMU
|
|
void lwp_user_setting_save(rt_thread_t thread)
|
|
{
|
|
if (thread)
|
|
{
|
|
thread->thread_idr = arch_get_tidr();
|
|
}
|
|
}
|
|
|
|
void lwp_user_setting_restore(rt_thread_t thread)
|
|
{
|
|
if (!thread)
|
|
{
|
|
return;
|
|
}
|
|
#if !defined(ARCH_RISCV64)
|
|
/* tidr will be set in RESTORE_ALL in risc-v */
|
|
arch_set_tidr(thread->thread_idr);
|
|
#endif
|
|
|
|
if (rt_dbg_ops)
|
|
{
|
|
struct rt_lwp *l = (struct rt_lwp *)thread->lwp;
|
|
|
|
if (l != 0)
|
|
{
|
|
rt_hw_set_process_id((size_t)l->pid);
|
|
}
|
|
else
|
|
{
|
|
rt_hw_set_process_id(0);
|
|
}
|
|
if (l && l->debug)
|
|
{
|
|
uint32_t step_type = 0;
|
|
|
|
step_type = dbg_step_type();
|
|
|
|
if ((step_type == 2) || (thread->step_exec && (step_type == 1)))
|
|
{
|
|
dbg_activate_step();
|
|
}
|
|
else
|
|
{
|
|
dbg_deactivate_step();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif /* ARCH_MM_MMU */
|
|
|
|
void lwp_uthread_ctx_save(void *ctx)
|
|
{
|
|
rt_thread_t thread;
|
|
thread = rt_thread_self();
|
|
thread->user_ctx.ctx = ctx;
|
|
}
|
|
|
|
void lwp_uthread_ctx_restore(void)
|
|
{
|
|
rt_thread_t thread;
|
|
thread = rt_thread_self();
|
|
thread->user_ctx.ctx = RT_NULL;
|
|
}
|
|
|
|
rt_err_t lwp_backtrace_frame(rt_thread_t uthread, struct rt_hw_backtrace_frame *frame)
|
|
{
|
|
rt_err_t rc = -RT_ERROR;
|
|
long nesting = 0;
|
|
char **argv;
|
|
rt_lwp_t lwp;
|
|
|
|
if (uthread && uthread->lwp && rt_scheduler_is_available())
|
|
{
|
|
lwp = uthread->lwp;
|
|
argv = lwp_get_command_line_args(lwp);
|
|
if (argv)
|
|
{
|
|
rt_kprintf("please use: addr2line -e %s -a -f", argv[0]);
|
|
lwp_free_command_line_args(argv);
|
|
}
|
|
else
|
|
{
|
|
rt_kprintf("please use: addr2line -e %s -a -f", lwp->cmd);
|
|
}
|
|
|
|
while (nesting < RT_BACKTRACE_LEVEL_MAX_NR)
|
|
{
|
|
rt_kprintf(" 0x%lx", frame->pc);
|
|
if (rt_hw_backtrace_frame_unwind(uthread, frame))
|
|
{
|
|
break;
|
|
}
|
|
nesting++;
|
|
}
|
|
rt_kprintf("\n");
|
|
rc = RT_EOK;
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
void rt_update_process_times(void)
|
|
{
|
|
struct rt_thread *thread;
|
|
#ifdef RT_USING_SMP
|
|
struct rt_cpu* pcpu;
|
|
|
|
pcpu = rt_cpu_self();
|
|
#endif
|
|
|
|
thread = rt_thread_self();
|
|
|
|
if (!IS_USER_MODE(thread))
|
|
{
|
|
thread->user_time += 1;
|
|
#ifdef RT_USING_SMP
|
|
pcpu->cpu_stat.user += 1;
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
thread->system_time += 1;
|
|
#ifdef RT_USING_SMP
|
|
if (thread == pcpu->idle_thread)
|
|
{
|
|
pcpu->cpu_stat.idle += 1;
|
|
}
|
|
else
|
|
{
|
|
pcpu->cpu_stat.system += 1;
|
|
}
|
|
#endif
|
|
}
|
|
}
|