[smart] fixup of script execution (#9009)
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>
This commit is contained in:
parent
85b428df42
commit
e5cf86267b
|
@ -56,8 +56,6 @@
|
||||||
#define O_BINARY 0x10000
|
#define O_BINARY 0x10000
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
static const char elf_magic[] = {0x7f, 'E', 'L', 'F'};
|
|
||||||
#ifdef DFS_USING_WORKDIR
|
#ifdef DFS_USING_WORKDIR
|
||||||
extern char working_directory[];
|
extern char working_directory[];
|
||||||
#endif
|
#endif
|
||||||
|
@ -245,893 +243,6 @@ uint32_t *lwp_get_kernel_sp(void)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ARCH_MM_MMU
|
|
||||||
struct process_aux *lwp_argscopy(struct rt_lwp *lwp, int argc, char **argv, char **envp)
|
|
||||||
{
|
|
||||||
int size = sizeof(size_t) * 5; /* store argc, argv, envp, aux, NULL */
|
|
||||||
int *args;
|
|
||||||
char *str;
|
|
||||||
char *str_k;
|
|
||||||
char **new_argve;
|
|
||||||
int i;
|
|
||||||
int len;
|
|
||||||
size_t *args_k;
|
|
||||||
struct process_aux *aux;
|
|
||||||
size_t prot = PROT_READ | PROT_WRITE;
|
|
||||||
size_t flags = MAP_FIXED | MAP_PRIVATE;
|
|
||||||
size_t zero = 0;
|
|
||||||
|
|
||||||
for (i = 0; i < argc; i++)
|
|
||||||
{
|
|
||||||
size += (rt_strlen(argv[i]) + 1);
|
|
||||||
}
|
|
||||||
size += (sizeof(size_t) * argc);
|
|
||||||
|
|
||||||
i = 0;
|
|
||||||
if (envp)
|
|
||||||
{
|
|
||||||
while (envp[i] != 0)
|
|
||||||
{
|
|
||||||
size += (rt_strlen(envp[i]) + 1);
|
|
||||||
size += sizeof(size_t);
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* for aux */
|
|
||||||
size += sizeof(struct process_aux);
|
|
||||||
|
|
||||||
if (size > ARCH_PAGE_SIZE)
|
|
||||||
{
|
|
||||||
return RT_NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
args = lwp_mmap2(lwp, (void *)(USER_STACK_VEND), size, prot, flags, -1, 0);
|
|
||||||
if (args == RT_NULL || lwp_data_put(lwp, args, &zero, sizeof(zero)) != sizeof(zero))
|
|
||||||
{
|
|
||||||
return RT_NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
args_k = (size_t *)lwp_v2p(lwp, args);
|
|
||||||
args_k = (size_t *)((size_t)args_k - PV_OFFSET);
|
|
||||||
|
|
||||||
/* argc, argv[], 0, envp[], 0 , aux[] */
|
|
||||||
str = (char *)((size_t)args + (argc + 2 + i + 1 + AUX_ARRAY_ITEMS_NR * 2 + 1) * sizeof(size_t));
|
|
||||||
str_k = (char *)((size_t)args_k + (argc + 2 + i + 1 + AUX_ARRAY_ITEMS_NR * 2 + 1) * sizeof(size_t));
|
|
||||||
|
|
||||||
new_argve = (char **)&args_k[1];
|
|
||||||
args_k[0] = argc;
|
|
||||||
|
|
||||||
for (i = 0; i < argc; i++)
|
|
||||||
{
|
|
||||||
len = rt_strlen(argv[i]) + 1;
|
|
||||||
new_argve[i] = str;
|
|
||||||
lwp_memcpy(str_k, argv[i], len);
|
|
||||||
str += len;
|
|
||||||
str_k += len;
|
|
||||||
}
|
|
||||||
new_argve[i] = 0;
|
|
||||||
i++;
|
|
||||||
|
|
||||||
new_argve[i] = 0;
|
|
||||||
if (envp)
|
|
||||||
{
|
|
||||||
int j;
|
|
||||||
|
|
||||||
for (j = 0; envp[j] != 0; j++)
|
|
||||||
{
|
|
||||||
len = rt_strlen(envp[j]) + 1;
|
|
||||||
new_argve[i] = str;
|
|
||||||
lwp_memcpy(str_k, envp[j], len);
|
|
||||||
str += len;
|
|
||||||
str_k += len;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
new_argve[i] = 0;
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
|
|
||||||
/* aux */
|
|
||||||
aux = (struct process_aux *)(new_argve + i);
|
|
||||||
aux->item[0].key = AT_EXECFN;
|
|
||||||
aux->item[0].value = (size_t)(size_t)new_argve[0];
|
|
||||||
i += AUX_ARRAY_ITEMS_NR * 2;
|
|
||||||
new_argve[i] = 0;
|
|
||||||
|
|
||||||
rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, args_k, size);
|
|
||||||
|
|
||||||
lwp->args = args;
|
|
||||||
|
|
||||||
return aux;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
static struct process_aux *lwp_argscopy(struct rt_lwp *lwp, int argc, char **argv, char **envp)
|
|
||||||
{
|
|
||||||
#ifdef ARCH_MM_MMU
|
|
||||||
int size = sizeof(int) * 5; /* store argc, argv, envp, aux, NULL */
|
|
||||||
struct process_aux *aux;
|
|
||||||
#else
|
|
||||||
int size = sizeof(int) * 4; /* store argc, argv, envp, NULL */
|
|
||||||
#endif /* ARCH_MM_MMU */
|
|
||||||
int *args;
|
|
||||||
char *str;
|
|
||||||
char **new_argve;
|
|
||||||
int i;
|
|
||||||
int len;
|
|
||||||
|
|
||||||
for (i = 0; i < argc; i++)
|
|
||||||
{
|
|
||||||
size += (rt_strlen(argv[i]) + 1);
|
|
||||||
}
|
|
||||||
size += (sizeof(int) * argc);
|
|
||||||
|
|
||||||
i = 0;
|
|
||||||
if (envp)
|
|
||||||
{
|
|
||||||
while (envp[i] != 0)
|
|
||||||
{
|
|
||||||
size += (rt_strlen(envp[i]) + 1);
|
|
||||||
size += sizeof(int);
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef ARCH_MM_MMU
|
|
||||||
/* for aux */
|
|
||||||
size += sizeof(struct process_aux);
|
|
||||||
|
|
||||||
args = (int *)rt_malloc(size);
|
|
||||||
if (args == RT_NULL)
|
|
||||||
{
|
|
||||||
return RT_NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* argc, argv[], 0, envp[], 0 */
|
|
||||||
str = (char *)((size_t)args + (argc + 2 + i + 1 + AUX_ARRAY_ITEMS_NR * 2 + 1) * sizeof(int));
|
|
||||||
#else
|
|
||||||
args = (int *)rt_malloc(size);
|
|
||||||
if (args == RT_NULL)
|
|
||||||
{
|
|
||||||
return RT_NULL;
|
|
||||||
}
|
|
||||||
str = (char*)((int)args + (argc + 2 + i + 1) * sizeof(int));
|
|
||||||
#endif /* ARCH_MM_MMU */
|
|
||||||
|
|
||||||
new_argve = (char **)&args[1];
|
|
||||||
args[0] = argc;
|
|
||||||
|
|
||||||
for (i = 0; i < argc; i++)
|
|
||||||
{
|
|
||||||
len = rt_strlen(argv[i]) + 1;
|
|
||||||
new_argve[i] = str;
|
|
||||||
lwp_memcpy(str, argv[i], len);
|
|
||||||
str += len;
|
|
||||||
}
|
|
||||||
new_argve[i] = 0;
|
|
||||||
i++;
|
|
||||||
|
|
||||||
new_argve[i] = 0;
|
|
||||||
if (envp)
|
|
||||||
{
|
|
||||||
int j;
|
|
||||||
for (j = 0; envp[j] != 0; j++)
|
|
||||||
{
|
|
||||||
len = rt_strlen(envp[j]) + 1;
|
|
||||||
new_argve[i] = str;
|
|
||||||
lwp_memcpy(str, envp[j], len);
|
|
||||||
str += len;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
new_argve[i] = 0;
|
|
||||||
}
|
|
||||||
#ifdef ARCH_MM_MMU
|
|
||||||
/* aux */
|
|
||||||
aux = (struct process_aux *)(new_argve + i);
|
|
||||||
aux->item[0].key = AT_EXECFN;
|
|
||||||
aux->item[0].value = (uint32_t)(size_t)new_argve[0];
|
|
||||||
i += AUX_ARRAY_ITEMS_NR * 2;
|
|
||||||
new_argve[i] = 0;
|
|
||||||
|
|
||||||
lwp->args = args;
|
|
||||||
|
|
||||||
return aux;
|
|
||||||
#else
|
|
||||||
lwp->args = args;
|
|
||||||
lwp->args_length = size;
|
|
||||||
|
|
||||||
return (struct process_aux *)(new_argve + i);
|
|
||||||
#endif /* ARCH_MM_MMU */
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef ARCH_MM_MMU
|
|
||||||
#define check_off(voff, vlen) \
|
|
||||||
do \
|
|
||||||
{ \
|
|
||||||
if (voff > vlen) \
|
|
||||||
{ \
|
|
||||||
result = -RT_ERROR; \
|
|
||||||
goto _exit; \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define check_read(vrlen, vrlen_want) \
|
|
||||||
do \
|
|
||||||
{ \
|
|
||||||
if (vrlen < vrlen_want) \
|
|
||||||
{ \
|
|
||||||
result = -RT_ERROR; \
|
|
||||||
goto _exit; \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
static size_t load_fread(void *ptr, size_t size, size_t nmemb, int fd)
|
|
||||||
{
|
|
||||||
size_t read_block = 0;
|
|
||||||
|
|
||||||
while (nmemb)
|
|
||||||
{
|
|
||||||
size_t count;
|
|
||||||
|
|
||||||
count = read(fd, ptr, size * nmemb) / size;
|
|
||||||
if (count < nmemb)
|
|
||||||
{
|
|
||||||
LOG_E("ERROR: file size error!");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ptr = (void *)((uint8_t *)ptr + (count * size));
|
|
||||||
nmemb -= count;
|
|
||||||
read_block += count;
|
|
||||||
}
|
|
||||||
|
|
||||||
return read_block;
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
Elf_Word st_name;
|
|
||||||
Elf_Addr st_value;
|
|
||||||
Elf_Word st_size;
|
|
||||||
unsigned char st_info;
|
|
||||||
unsigned char st_other;
|
|
||||||
Elf_Half st_shndx;
|
|
||||||
} Elf_sym;
|
|
||||||
|
|
||||||
#ifdef ARCH_MM_MMU
|
|
||||||
struct map_range
|
|
||||||
{
|
|
||||||
void *start;
|
|
||||||
size_t size;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void expand_map_range(struct map_range *m, void *start, size_t size)
|
|
||||||
{
|
|
||||||
if (!m->start)
|
|
||||||
{
|
|
||||||
m->start = start;
|
|
||||||
m->size = size;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
void *end = (void *)((char*)start + size);
|
|
||||||
void *mend = (void *)((char*)m->start + m->size);
|
|
||||||
|
|
||||||
if (m->start > start)
|
|
||||||
{
|
|
||||||
m->start = start;
|
|
||||||
}
|
|
||||||
if (mend < end)
|
|
||||||
{
|
|
||||||
mend = end;
|
|
||||||
}
|
|
||||||
m->size = (char *)mend - (char *)m->start;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int map_range_ckeck(struct map_range *m1, struct map_range *m2)
|
|
||||||
{
|
|
||||||
void *m1_start = (void *)((size_t)m1->start & ~ARCH_PAGE_MASK);
|
|
||||||
void *m1_end = (void *)((((size_t)m1->start + m1->size) + ARCH_PAGE_MASK) & ~ARCH_PAGE_MASK);
|
|
||||||
void *m2_start = (void *)((size_t)m2->start & ~ARCH_PAGE_MASK);
|
|
||||||
void *m2_end = (void *)((((size_t)m2->start + m2->size) + ARCH_PAGE_MASK) & ~ARCH_PAGE_MASK);
|
|
||||||
|
|
||||||
if (m1->size)
|
|
||||||
{
|
|
||||||
if (m1_start < (void *)USER_LOAD_VADDR)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (m1_start > (void *)USER_STACK_VSTART)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (m1_end < (void *)USER_LOAD_VADDR)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (m1_end > (void *)USER_STACK_VSTART)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (m2->size)
|
|
||||||
{
|
|
||||||
if (m2_start < (void *)USER_LOAD_VADDR)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (m2_start > (void *)USER_STACK_VSTART)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (m2_end < (void *)USER_LOAD_VADDR)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (m2_end > (void *)USER_STACK_VSTART)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((m1->size != 0) && (m2->size != 0))
|
|
||||||
{
|
|
||||||
if (m1_start < m2_start)
|
|
||||||
{
|
|
||||||
if (m1_end > m2_start)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else /* m2_start <= m1_start */
|
|
||||||
{
|
|
||||||
if (m2_end > m1_start)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static int load_elf(int fd, int len, struct rt_lwp *lwp, uint8_t *load_addr, struct process_aux *aux)
|
|
||||||
{
|
|
||||||
uint32_t i;
|
|
||||||
uint32_t off = 0;
|
|
||||||
size_t load_off = 0;
|
|
||||||
char *p_section_str = 0;
|
|
||||||
Elf_sym *dynsym = 0;
|
|
||||||
Elf_Ehdr eheader;
|
|
||||||
Elf_Phdr pheader;
|
|
||||||
Elf_Shdr sheader;
|
|
||||||
int result = RT_EOK;
|
|
||||||
uint32_t magic;
|
|
||||||
size_t read_len;
|
|
||||||
void *got_start = 0;
|
|
||||||
size_t got_size = 0;
|
|
||||||
void *rel_dyn_start = 0;
|
|
||||||
size_t rel_dyn_size = 0;
|
|
||||||
size_t dynsym_off = 0;
|
|
||||||
size_t dynsym_size = 0;
|
|
||||||
#ifdef ARCH_MM_MMU
|
|
||||||
struct map_range user_area[2] = {{NULL, 0}, {NULL, 0}}; /* 0 is text, 1 is data */
|
|
||||||
void *pa, *va;
|
|
||||||
void *va_self;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (len < sizeof eheader)
|
|
||||||
{
|
|
||||||
LOG_E("len < sizeof eheader!");
|
|
||||||
return -RT_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
lseek(fd, 0, SEEK_SET);
|
|
||||||
read_len = load_fread(&magic, 1, sizeof magic, fd);
|
|
||||||
check_read(read_len, sizeof magic);
|
|
||||||
|
|
||||||
if (memcmp(elf_magic, &magic, 4) != 0)
|
|
||||||
{
|
|
||||||
LOG_E("elf_magic not same, magic:0x%x!", magic);
|
|
||||||
return -RT_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
lseek(fd, off, SEEK_SET);
|
|
||||||
read_len = load_fread(&eheader, 1, sizeof eheader, fd);
|
|
||||||
check_read(read_len, sizeof eheader);
|
|
||||||
|
|
||||||
#ifndef ARCH_CPU_64BIT
|
|
||||||
if (eheader.e_ident[4] != 1)
|
|
||||||
{ /* not 32bit */
|
|
||||||
LOG_E("elf not 32bit, %d!", eheader.e_ident[4]);
|
|
||||||
return -RT_ERROR;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
if (eheader.e_ident[4] != 2)
|
|
||||||
{ /* not 64bit */
|
|
||||||
LOG_E("elf not 64bit, %d!", eheader.e_ident[4]);
|
|
||||||
return -RT_ERROR;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (eheader.e_ident[6] != 1)
|
|
||||||
{ /* ver not 1 */
|
|
||||||
LOG_E("elf Version not 1,ver:%d!", eheader.e_ident[6]);
|
|
||||||
return -RT_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((eheader.e_type != ET_DYN)
|
|
||||||
#ifdef ARCH_MM_MMU
|
|
||||||
&& (eheader.e_type != ET_EXEC)
|
|
||||||
#endif
|
|
||||||
)
|
|
||||||
{
|
|
||||||
/* not pie or exec elf */
|
|
||||||
LOG_E("elf type not pie or exec, type:%d!", eheader.e_type);
|
|
||||||
return -RT_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef ARCH_MM_MMU
|
|
||||||
{
|
|
||||||
off = eheader.e_phoff;
|
|
||||||
for (i = 0; i < eheader.e_phnum; i++, off += sizeof pheader)
|
|
||||||
{
|
|
||||||
check_off(off, len);
|
|
||||||
lseek(fd, off, SEEK_SET);
|
|
||||||
read_len = load_fread(&pheader, 1, sizeof pheader, fd);
|
|
||||||
check_read(read_len, sizeof pheader);
|
|
||||||
|
|
||||||
if (pheader.p_type == PT_DYNAMIC)
|
|
||||||
{
|
|
||||||
/* load ld.so */
|
|
||||||
return 1; /* 1 means dynamic */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (eheader.e_entry != 0)
|
|
||||||
{
|
|
||||||
if ((eheader.e_entry != USER_LOAD_VADDR)
|
|
||||||
&& (eheader.e_entry != LDSO_LOAD_VADDR))
|
|
||||||
{
|
|
||||||
/* the entry is invalidate */
|
|
||||||
LOG_E("elf entry is invalidate, entry:0x%x!", eheader.e_entry);
|
|
||||||
return -RT_ERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{ /* load aux */
|
|
||||||
uint8_t *process_header;
|
|
||||||
size_t process_header_size;
|
|
||||||
|
|
||||||
off = eheader.e_phoff;
|
|
||||||
process_header_size = eheader.e_phnum * sizeof pheader;
|
|
||||||
#ifdef ARCH_MM_MMU
|
|
||||||
if (process_header_size > ARCH_PAGE_SIZE - sizeof(char[16]))
|
|
||||||
{
|
|
||||||
LOG_E("process_header_size too big, size:0x%x!", process_header_size);
|
|
||||||
return -RT_ERROR;
|
|
||||||
}
|
|
||||||
va = (uint8_t *)lwp_map_user(lwp, (void *)(USER_VADDR_TOP - ARCH_PAGE_SIZE * 2), process_header_size, 0);
|
|
||||||
if (!va)
|
|
||||||
{
|
|
||||||
LOG_E("lwp map user failed!");
|
|
||||||
return -RT_ERROR;
|
|
||||||
}
|
|
||||||
pa = lwp_v2p(lwp, va);
|
|
||||||
process_header = (uint8_t *)pa - PV_OFFSET;
|
|
||||||
#else
|
|
||||||
process_header = (uint8_t *)rt_malloc(process_header_size + sizeof(char[16]));
|
|
||||||
if (!process_header)
|
|
||||||
{
|
|
||||||
LOG_E("process_header malloc failed, size:0x%x!", process_header_size + sizeof(char[16]));
|
|
||||||
return -RT_ERROR;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
check_off(off, len);
|
|
||||||
lseek(fd, off, SEEK_SET);
|
|
||||||
read_len = load_fread(process_header, 1, process_header_size, fd);
|
|
||||||
check_read(read_len, process_header_size);
|
|
||||||
#ifdef ARCH_MM_MMU
|
|
||||||
rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, process_header, process_header_size);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
aux->item[1].key = AT_PAGESZ;
|
|
||||||
#ifdef ARCH_MM_MMU
|
|
||||||
aux->item[1].value = ARCH_PAGE_SIZE;
|
|
||||||
#else
|
|
||||||
aux->item[1].value = RT_MM_PAGE_SIZE;
|
|
||||||
#endif
|
|
||||||
aux->item[2].key = AT_RANDOM;
|
|
||||||
{
|
|
||||||
uint32_t random_value = rt_tick_get();
|
|
||||||
uint8_t *random;
|
|
||||||
#ifdef ARCH_MM_MMU
|
|
||||||
uint8_t *krandom;
|
|
||||||
|
|
||||||
random = (uint8_t *)(USER_VADDR_TOP - ARCH_PAGE_SIZE - sizeof(char[16]));
|
|
||||||
|
|
||||||
krandom = (uint8_t *)lwp_v2p(lwp, random);
|
|
||||||
krandom = (uint8_t *)krandom - PV_OFFSET;
|
|
||||||
rt_memcpy(krandom, &random_value, sizeof random_value);
|
|
||||||
#else
|
|
||||||
random = (uint8_t *)(process_header + process_header_size);
|
|
||||||
rt_memcpy(random, &random_value, sizeof random_value);
|
|
||||||
#endif
|
|
||||||
aux->item[2].value = (size_t)random;
|
|
||||||
}
|
|
||||||
aux->item[3].key = AT_PHDR;
|
|
||||||
#ifdef ARCH_MM_MMU
|
|
||||||
aux->item[3].value = (size_t)va;
|
|
||||||
#else
|
|
||||||
aux->item[3].value = (size_t)process_header;
|
|
||||||
#endif
|
|
||||||
aux->item[4].key = AT_PHNUM;
|
|
||||||
aux->item[4].value = eheader.e_phnum;
|
|
||||||
aux->item[5].key = AT_PHENT;
|
|
||||||
aux->item[5].value = sizeof pheader;
|
|
||||||
#ifdef ARCH_MM_MMU
|
|
||||||
rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, aux, sizeof *aux);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
if (load_addr)
|
|
||||||
{
|
|
||||||
load_off = (size_t)load_addr;
|
|
||||||
}
|
|
||||||
#ifdef ARCH_MM_MMU
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* map user */
|
|
||||||
off = eheader.e_shoff;
|
|
||||||
for (i = 0; i < eheader.e_shnum; i++, off += sizeof sheader)
|
|
||||||
{
|
|
||||||
check_off(off, len);
|
|
||||||
lseek(fd, off, SEEK_SET);
|
|
||||||
read_len = load_fread(&sheader, 1, sizeof sheader, fd);
|
|
||||||
check_read(read_len, sizeof sheader);
|
|
||||||
|
|
||||||
if ((sheader.sh_flags & SHF_ALLOC) == 0)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (sheader.sh_type)
|
|
||||||
{
|
|
||||||
case SHT_PROGBITS:
|
|
||||||
if ((sheader.sh_flags & SHF_WRITE) == 0)
|
|
||||||
{
|
|
||||||
expand_map_range(&user_area[0], (void *)sheader.sh_addr, sheader.sh_size);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
expand_map_range(&user_area[1], (void *)sheader.sh_addr, sheader.sh_size);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SHT_NOBITS:
|
|
||||||
expand_map_range(&user_area[1], (void *)sheader.sh_addr, sheader.sh_size);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
expand_map_range(&user_area[1], (void *)sheader.sh_addr, sheader.sh_size);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (user_area[0].size == 0)
|
|
||||||
{
|
|
||||||
/* no code */
|
|
||||||
result = -RT_ERROR;
|
|
||||||
goto _exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (user_area[0].start == NULL)
|
|
||||||
{
|
|
||||||
/* DYN */
|
|
||||||
load_off = USER_LOAD_VADDR;
|
|
||||||
user_area[0].start = (void *)((char*)user_area[0].start + load_off);
|
|
||||||
user_area[1].start = (void *)((char*)user_area[1].start + load_off);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (map_range_ckeck(&user_area[0], &user_area[1]) != 0)
|
|
||||||
{
|
|
||||||
result = -RT_ERROR;
|
|
||||||
goto _exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* text and data */
|
|
||||||
for (i = 0; i < 2; i++)
|
|
||||||
{
|
|
||||||
if (user_area[i].size != 0)
|
|
||||||
{
|
|
||||||
va = lwp_map_user(lwp, user_area[i].start, user_area[i].size, (i == 0));
|
|
||||||
if (!va || (va != user_area[i].start))
|
|
||||||
{
|
|
||||||
result = -RT_ERROR;
|
|
||||||
goto _exit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lwp->text_size = user_area[0].size;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
else
|
|
||||||
{
|
|
||||||
size_t start = -1UL;
|
|
||||||
size_t end = 0UL;
|
|
||||||
size_t total_size;
|
|
||||||
|
|
||||||
off = eheader.e_shoff;
|
|
||||||
for (i = 0; i < eheader.e_shnum; i++, off += sizeof sheader)
|
|
||||||
{
|
|
||||||
check_off(off, len);
|
|
||||||
lseek(fd, off, SEEK_SET);
|
|
||||||
read_len = load_fread(&sheader, 1, sizeof sheader, fd);
|
|
||||||
check_read(read_len, sizeof sheader);
|
|
||||||
|
|
||||||
if ((sheader.sh_flags & SHF_ALLOC) == 0)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (sheader.sh_type)
|
|
||||||
{
|
|
||||||
case SHT_PROGBITS:
|
|
||||||
case SHT_NOBITS:
|
|
||||||
if (start > sheader.sh_addr)
|
|
||||||
{
|
|
||||||
start = sheader.sh_addr;
|
|
||||||
}
|
|
||||||
if (sheader.sh_addr + sheader.sh_size > end)
|
|
||||||
{
|
|
||||||
end = sheader.sh_addr + sheader.sh_size;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
total_size = end - start;
|
|
||||||
|
|
||||||
#ifdef RT_USING_CACHE
|
|
||||||
load_off = (size_t)rt_malloc_align(total_size, RT_CPU_CACHE_LINE_SZ);
|
|
||||||
#else
|
|
||||||
load_off = (size_t)rt_malloc(total_size);
|
|
||||||
#endif
|
|
||||||
if (load_off == 0)
|
|
||||||
{
|
|
||||||
LOG_E("alloc text memory faild!");
|
|
||||||
result = -RT_ENOMEM;
|
|
||||||
goto _exit;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LOG_D("lwp text malloc : %p, size: %d!", (void *)load_off, lwp->text_size);
|
|
||||||
}
|
|
||||||
lwp->load_off = load_off; /* for free */
|
|
||||||
lwp->text_size = total_size;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
lwp->text_entry = (void *)(eheader.e_entry + load_off);
|
|
||||||
|
|
||||||
off = eheader.e_phoff;
|
|
||||||
for (i = 0; i < eheader.e_phnum; i++, off += sizeof pheader)
|
|
||||||
{
|
|
||||||
check_off(off, len);
|
|
||||||
lseek(fd, off, SEEK_SET);
|
|
||||||
read_len = load_fread(&pheader, 1, sizeof pheader, fd);
|
|
||||||
check_read(read_len, sizeof pheader);
|
|
||||||
|
|
||||||
if (pheader.p_type == PT_LOAD)
|
|
||||||
{
|
|
||||||
if (pheader.p_filesz > pheader.p_memsz)
|
|
||||||
{
|
|
||||||
LOG_E("pheader.p_filesz > pheader.p_memsz, p_filesz:0x%x;p_memsz:0x%x!", pheader.p_filesz, pheader.p_memsz);
|
|
||||||
return -RT_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
check_off(pheader.p_offset, len);
|
|
||||||
lseek(fd, pheader.p_offset, SEEK_SET);
|
|
||||||
#ifdef ARCH_MM_MMU
|
|
||||||
{
|
|
||||||
uint32_t size = pheader.p_filesz;
|
|
||||||
size_t tmp_len = 0;
|
|
||||||
|
|
||||||
va = (void *)(pheader.p_vaddr + load_addr);
|
|
||||||
read_len = 0;
|
|
||||||
while (size)
|
|
||||||
{
|
|
||||||
pa = lwp_v2p(lwp, va);
|
|
||||||
va_self = (void *)((char *)pa - PV_OFFSET);
|
|
||||||
LOG_D("va_self = %p pa = %p", va_self, pa);
|
|
||||||
tmp_len = (size < ARCH_PAGE_SIZE) ? size : ARCH_PAGE_SIZE;
|
|
||||||
tmp_len = load_fread(va_self, 1, tmp_len, fd);
|
|
||||||
rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, va_self, tmp_len);
|
|
||||||
read_len += tmp_len;
|
|
||||||
size -= tmp_len;
|
|
||||||
va = (void *)((char *)va + ARCH_PAGE_SIZE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
read_len = load_fread((void*)(pheader.p_vaddr + load_off), 1, pheader.p_filesz, fd);
|
|
||||||
#endif
|
|
||||||
check_read(read_len, pheader.p_filesz);
|
|
||||||
|
|
||||||
if (pheader.p_filesz < pheader.p_memsz)
|
|
||||||
{
|
|
||||||
#ifdef ARCH_MM_MMU
|
|
||||||
uint32_t size = pheader.p_memsz - pheader.p_filesz;
|
|
||||||
uint32_t size_s;
|
|
||||||
uint32_t off;
|
|
||||||
|
|
||||||
off = pheader.p_filesz & ARCH_PAGE_MASK;
|
|
||||||
va = (void *)((pheader.p_vaddr + pheader.p_filesz + load_off) & ~ARCH_PAGE_MASK);
|
|
||||||
while (size)
|
|
||||||
{
|
|
||||||
size_s = (size < ARCH_PAGE_SIZE - off) ? size : ARCH_PAGE_SIZE - off;
|
|
||||||
pa = lwp_v2p(lwp, va);
|
|
||||||
va_self = (void *)((char *)pa - PV_OFFSET);
|
|
||||||
memset((void *)((char *)va_self + off), 0, size_s);
|
|
||||||
rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, (void *)((char *)va_self + off), size_s);
|
|
||||||
off = 0;
|
|
||||||
size -= size_s;
|
|
||||||
va = (void *)((char *)va + ARCH_PAGE_SIZE);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
memset((uint8_t *)pheader.p_vaddr + pheader.p_filesz + load_off, 0, (size_t)(pheader.p_memsz - pheader.p_filesz));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* relocate */
|
|
||||||
if (eheader.e_type == ET_DYN)
|
|
||||||
{
|
|
||||||
/* section info */
|
|
||||||
off = eheader.e_shoff;
|
|
||||||
/* find section string table */
|
|
||||||
check_off(off, len);
|
|
||||||
lseek(fd, off + (sizeof sheader) * eheader.e_shstrndx, SEEK_SET);
|
|
||||||
read_len = load_fread(&sheader, 1, sizeof sheader, fd);
|
|
||||||
check_read(read_len, sizeof sheader);
|
|
||||||
|
|
||||||
p_section_str = (char *)rt_malloc(sheader.sh_size);
|
|
||||||
if (!p_section_str)
|
|
||||||
{
|
|
||||||
LOG_E("out of memory!");
|
|
||||||
result = -ENOMEM;
|
|
||||||
goto _exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
check_off(sheader.sh_offset, len);
|
|
||||||
lseek(fd, sheader.sh_offset, SEEK_SET);
|
|
||||||
read_len = load_fread(p_section_str, 1, sheader.sh_size, fd);
|
|
||||||
check_read(read_len, sheader.sh_size);
|
|
||||||
|
|
||||||
check_off(off, len);
|
|
||||||
lseek(fd, off, SEEK_SET);
|
|
||||||
for (i = 0; i < eheader.e_shnum; i++, off += sizeof sheader)
|
|
||||||
{
|
|
||||||
read_len = load_fread(&sheader, 1, sizeof sheader, fd);
|
|
||||||
check_read(read_len, sizeof sheader);
|
|
||||||
|
|
||||||
if (strcmp(p_section_str + sheader.sh_name, ".got") == 0)
|
|
||||||
{
|
|
||||||
got_start = (void *)((uint8_t *)sheader.sh_addr + load_off);
|
|
||||||
got_size = (size_t)sheader.sh_size;
|
|
||||||
}
|
|
||||||
else if (strcmp(p_section_str + sheader.sh_name, ".rel.dyn") == 0)
|
|
||||||
{
|
|
||||||
rel_dyn_start = (void *)((uint8_t *)sheader.sh_addr + load_off);
|
|
||||||
rel_dyn_size = (size_t)sheader.sh_size;
|
|
||||||
}
|
|
||||||
else if (strcmp(p_section_str + sheader.sh_name, ".dynsym") == 0)
|
|
||||||
{
|
|
||||||
dynsym_off = (size_t)sheader.sh_offset;
|
|
||||||
dynsym_size = (size_t)sheader.sh_size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* reloc */
|
|
||||||
if (dynsym_size)
|
|
||||||
{
|
|
||||||
dynsym = rt_malloc(dynsym_size);
|
|
||||||
if (!dynsym)
|
|
||||||
{
|
|
||||||
LOG_E("ERROR: Malloc error!");
|
|
||||||
result = -ENOMEM;
|
|
||||||
goto _exit;
|
|
||||||
}
|
|
||||||
check_off(dynsym_off, len);
|
|
||||||
lseek(fd, dynsym_off, SEEK_SET);
|
|
||||||
read_len = load_fread(dynsym, 1, dynsym_size, fd);
|
|
||||||
check_read(read_len, dynsym_size);
|
|
||||||
}
|
|
||||||
#ifdef ARCH_MM_MMU
|
|
||||||
arch_elf_reloc(lwp->aspace, (void *)load_off, rel_dyn_start, rel_dyn_size, got_start, got_size, dynsym);
|
|
||||||
#else
|
|
||||||
arch_elf_reloc((void *)load_off, rel_dyn_start, rel_dyn_size, got_start, got_size, dynsym);
|
|
||||||
|
|
||||||
rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, lwp->text_entry, lwp->text_size);
|
|
||||||
rt_hw_cpu_icache_ops(RT_HW_CACHE_INVALIDATE, lwp->text_entry, lwp->text_size);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
LOG_D("lwp->text_entry = 0x%p", lwp->text_entry);
|
|
||||||
LOG_D("lwp->text_size = 0x%p", lwp->text_size);
|
|
||||||
|
|
||||||
_exit:
|
|
||||||
if (dynsym)
|
|
||||||
{
|
|
||||||
rt_free(dynsym);
|
|
||||||
}
|
|
||||||
if (p_section_str)
|
|
||||||
{
|
|
||||||
rt_free(p_section_str);
|
|
||||||
}
|
|
||||||
if (result != RT_EOK)
|
|
||||||
{
|
|
||||||
LOG_E("lwp load faild, %d", result);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
#endif /* ARCH_MM_MMU */
|
|
||||||
|
|
||||||
rt_weak int lwp_load(const char *filename, struct rt_lwp *lwp, uint8_t *load_addr, size_t addr_size, struct process_aux *aux)
|
|
||||||
{
|
|
||||||
uint8_t *ptr;
|
|
||||||
int ret = -1;
|
|
||||||
int len;
|
|
||||||
int fd = -1;
|
|
||||||
|
|
||||||
/* check file name */
|
|
||||||
RT_ASSERT(filename != RT_NULL);
|
|
||||||
/* check lwp control block */
|
|
||||||
RT_ASSERT(lwp != RT_NULL);
|
|
||||||
|
|
||||||
/* copy file name to process name */
|
|
||||||
rt_strncpy(lwp->cmd, filename, RT_NAME_MAX);
|
|
||||||
|
|
||||||
if (load_addr != RT_NULL)
|
|
||||||
{
|
|
||||||
lwp->lwp_type = LWP_TYPE_FIX_ADDR;
|
|
||||||
ptr = load_addr;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
lwp->lwp_type = LWP_TYPE_DYN_ADDR;
|
|
||||||
ptr = RT_NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
fd = open(filename, O_BINARY | O_RDONLY, 0);
|
|
||||||
if (fd < 0)
|
|
||||||
{
|
|
||||||
LOG_E("ERROR: Can't open elf file %s!", filename);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
len = lseek(fd, 0, SEEK_END);
|
|
||||||
if (len < 0)
|
|
||||||
{
|
|
||||||
LOG_E("ERROR: File %s size error!", filename);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
lseek(fd, 0, SEEK_SET);
|
|
||||||
|
|
||||||
ret = load_elf(fd, len, lwp, ptr, aux);
|
|
||||||
if ((ret != RT_EOK) && (ret != 1))
|
|
||||||
{
|
|
||||||
LOG_E("lwp load ret = %d", ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
out:
|
|
||||||
if (fd > 0)
|
|
||||||
{
|
|
||||||
close(fd);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* lwp-thread clean up routine */
|
/* lwp-thread clean up routine */
|
||||||
void lwp_cleanup(struct rt_thread *tid)
|
void lwp_cleanup(struct rt_thread *tid)
|
||||||
|
@ -1286,6 +397,34 @@ rt_err_t lwp_children_unregister(struct rt_lwp *parent, struct rt_lwp *child)
|
||||||
return 0;
|
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)
|
pid_t lwp_execve(char *filename, int debug, int argc, char **argv, char **envp)
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
|
@ -1327,7 +466,7 @@ pid_t lwp_execve(char *filename, int debug, int argc, char **argv, char **envp)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if ((aux = lwp_argscopy(lwp, argc, argv, envp)) == RT_NULL)
|
if ((aux = argscopy(lwp, argc, argv, envp)) == RT_NULL)
|
||||||
{
|
{
|
||||||
lwp_tid_put(tid);
|
lwp_tid_put(tid);
|
||||||
lwp_ref_dec(lwp);
|
lwp_ref_dec(lwp);
|
||||||
|
@ -1335,14 +474,6 @@ pid_t lwp_execve(char *filename, int debug, int argc, char **argv, char **envp)
|
||||||
}
|
}
|
||||||
|
|
||||||
result = lwp_load(filename, lwp, RT_NULL, 0, aux);
|
result = lwp_load(filename, lwp, RT_NULL, 0, aux);
|
||||||
#ifdef ARCH_MM_MMU
|
|
||||||
if (result == 1)
|
|
||||||
{
|
|
||||||
/* dynmaic */
|
|
||||||
lwp_unmap_user(lwp, (void *)(USER_VADDR_TOP - ARCH_PAGE_SIZE));
|
|
||||||
result = load_ldso(lwp, filename, argv, envp);
|
|
||||||
}
|
|
||||||
#endif /* ARCH_MM_MMU */
|
|
||||||
if (result == RT_EOK)
|
if (result == RT_EOK)
|
||||||
{
|
{
|
||||||
rt_thread_t thread = RT_NULL;
|
rt_thread_t thread = RT_NULL;
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
#include "lwp_signal.h"
|
#include "lwp_signal.h"
|
||||||
#include "lwp_syscall.h"
|
#include "lwp_syscall.h"
|
||||||
#include "lwp_avl.h"
|
#include "lwp_avl.h"
|
||||||
|
#include "lwp_args.h"
|
||||||
#include "mm_aspace.h"
|
#include "mm_aspace.h"
|
||||||
|
|
||||||
#ifdef RT_USING_MUSLLIBC
|
#ifdef RT_USING_MUSLLIBC
|
||||||
|
@ -237,6 +238,8 @@ void lwp_tid_dec_ref(rt_thread_t thread);
|
||||||
void lwp_tid_set_thread(int tid, rt_thread_t thread);
|
void lwp_tid_set_thread(int tid, rt_thread_t thread);
|
||||||
|
|
||||||
int lwp_execve(char *filename, int debug, int argc, char **argv, char **envp);
|
int lwp_execve(char *filename, int debug, int argc, char **argv, char **envp);
|
||||||
|
int lwp_load(const char *filename, struct rt_lwp *lwp, uint8_t *load_addr, size_t addr_size, struct process_aux *aux);
|
||||||
|
void lwp_user_obj_free(struct rt_lwp *lwp);
|
||||||
|
|
||||||
/*create by lwp_setsid.c*/
|
/*create by lwp_setsid.c*/
|
||||||
int setsid(void);
|
int setsid(void);
|
||||||
|
@ -382,15 +385,6 @@ struct process_aux
|
||||||
struct process_aux_item item[AUX_ARRAY_ITEMS_NR];
|
struct process_aux_item item[AUX_ARRAY_ITEMS_NR];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct lwp_args_info
|
|
||||||
{
|
|
||||||
char **argv;
|
|
||||||
char **envp;
|
|
||||||
int argc;
|
|
||||||
int envc;
|
|
||||||
int size;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct dbg_ops_t
|
struct dbg_ops_t
|
||||||
{
|
{
|
||||||
int (*dbg)(int argc, char **argv);
|
int (*dbg)(int argc, char **argv);
|
||||||
|
|
|
@ -0,0 +1,781 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2006-2024, RT-Thread Development Team
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Change Logs:
|
||||||
|
* Date Author Notes
|
||||||
|
* 2024-01-12 Shell separate argv, envp, aux processing to lwp_args.c
|
||||||
|
* Bugs fix for script arguments processing.
|
||||||
|
* support args larger than 4k
|
||||||
|
*/
|
||||||
|
#include "lwp_args.h"
|
||||||
|
#include "lwp_internal.h"
|
||||||
|
#include "mm_page.h"
|
||||||
|
|
||||||
|
static void _strvec_init(struct lwp_string_vector *sv)
|
||||||
|
{
|
||||||
|
#define DEFAUTL_ARGV_BUFLEN 4
|
||||||
|
sv->strvec = rt_malloc(DEFAUTL_ARGV_BUFLEN * sizeof(char *));
|
||||||
|
sv->strvec_buflen = DEFAUTL_ARGV_BUFLEN;
|
||||||
|
sv->string_count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _strvec_detach(struct lwp_string_vector *sv)
|
||||||
|
{
|
||||||
|
if (sv->strvec)
|
||||||
|
{
|
||||||
|
rt_free(sv->strvec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static rt_err_t _strvec_append(struct lwp_string_vector *sv, const char *string)
|
||||||
|
{
|
||||||
|
if (sv->string_count == sv->strvec_buflen)
|
||||||
|
{
|
||||||
|
void *newptr;
|
||||||
|
newptr = rt_realloc(sv->strvec, sv->strvec_buflen * 2 * sizeof(char *));
|
||||||
|
if (!newptr)
|
||||||
|
return -RT_ENOMEM;
|
||||||
|
sv->strvec = newptr;
|
||||||
|
sv->strvec_buflen *= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
sv->strvec[sv->string_count++] = string;
|
||||||
|
return RT_EOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static rt_err_t args_append(struct lwp_args_info *ai, const char *str_addr,
|
||||||
|
size_t str_len, enum lwp_args_type atype)
|
||||||
|
{
|
||||||
|
rt_err_t error;
|
||||||
|
char *str_bufaddr;
|
||||||
|
|
||||||
|
if (ai->strings_length + str_len + 1 > ai->str_buf_size)
|
||||||
|
{
|
||||||
|
/* reallocate buffer for this */
|
||||||
|
void *newptr;
|
||||||
|
newptr = rt_realloc(ai->str_buf, ai->str_buf_size * 2);
|
||||||
|
if (!newptr)
|
||||||
|
return -RT_ENOMEM;
|
||||||
|
ai->str_buf = newptr;
|
||||||
|
ai->str_buf_size *= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* append new string to string buffer and update strings_length */
|
||||||
|
str_bufaddr = &ai->str_buf[ai->strings_length];
|
||||||
|
if (atype == LWP_ARGS_TYPE_KARG || atype == LWP_ARGS_TYPE_KENVP)
|
||||||
|
{
|
||||||
|
strcpy(str_bufaddr, str_addr);
|
||||||
|
ai->strings_length += str_len + 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lwp_get_from_user(str_bufaddr, (void *)str_addr, str_len);
|
||||||
|
ai->strings_length += str_len;
|
||||||
|
ai->str_buf[ai->strings_length++] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
/* append new argument or environment */
|
||||||
|
switch (atype)
|
||||||
|
{
|
||||||
|
case LWP_ARGS_TYPE_ARG:
|
||||||
|
case LWP_ARGS_TYPE_KARG:
|
||||||
|
error = _strvec_append(&ai->argv, str_bufaddr);
|
||||||
|
if (!error && ai->argv.string_count == 1)
|
||||||
|
{
|
||||||
|
ai->argv0_strlen = str_len;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case LWP_ARGS_TYPE_ENVP:
|
||||||
|
case LWP_ARGS_TYPE_KENVP:
|
||||||
|
error = _strvec_append(&ai->envp, str_bufaddr);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Override arguments 0 for script interpreter.
|
||||||
|
*
|
||||||
|
* Manual: 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.
|
||||||
|
*/
|
||||||
|
static rt_err_t _args_override_argv0(struct lwp_args_info *ai, struct lwp_args_info *ow_ai)
|
||||||
|
{
|
||||||
|
rt_err_t error = 0;
|
||||||
|
int i, new_argc, new_strbuf_size, ai_bytes_tobe_copied;
|
||||||
|
char **new_argv, *new_strbuf, *base;
|
||||||
|
rt_base_t off;
|
||||||
|
|
||||||
|
if (ow_ai == 0 || ow_ai->argv.string_count == 0)
|
||||||
|
{
|
||||||
|
return -RT_EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* for new argument vector */
|
||||||
|
new_argc = ai->argv.string_count - 1 + ow_ai->argv.string_count;
|
||||||
|
new_argv = rt_malloc(new_argc * sizeof(char *));
|
||||||
|
if (!new_argv)
|
||||||
|
{
|
||||||
|
return -RT_ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* for new string buffer */
|
||||||
|
ai_bytes_tobe_copied = ai->strings_length - (ai->argv0_strlen + 1);
|
||||||
|
new_strbuf_size = ai_bytes_tobe_copied + ow_ai->strings_length;
|
||||||
|
new_strbuf = rt_malloc(new_strbuf_size);
|
||||||
|
if (!new_argv)
|
||||||
|
{
|
||||||
|
rt_free(new_argv);
|
||||||
|
return -RT_ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
base = new_strbuf;
|
||||||
|
off = base - ow_ai->str_buf;
|
||||||
|
/* copy overriding argument strings and argv */
|
||||||
|
memcpy(base, ow_ai->str_buf, ow_ai->strings_length);
|
||||||
|
for (i = 0; i < ow_ai->argv.string_count; i++)
|
||||||
|
{
|
||||||
|
/* base + ow_ai->argv.strvec[i] - ow_ai->str_buf */
|
||||||
|
new_argv[i] = (char *)ow_ai->argv.strvec[i] + off;
|
||||||
|
}
|
||||||
|
|
||||||
|
base += ow_ai->strings_length;
|
||||||
|
off = base - (ai->str_buf + ai->argv0_strlen + 1);
|
||||||
|
/* copy old argument strings starting from argv[1] and setup new_argv */
|
||||||
|
memcpy(base, ai->str_buf + ai->argv0_strlen + 1, ai_bytes_tobe_copied);
|
||||||
|
for (size_t j = 1; j < ai->argv.string_count; i++, j++)
|
||||||
|
{
|
||||||
|
/* base + ai->argv->strvec[j] - ai->str_buf */
|
||||||
|
new_argv[i] = (char *)ai->argv.strvec[j] + off;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* setup envp for ai */
|
||||||
|
for (i = 0; i < ai->envp.string_count; i++)
|
||||||
|
{
|
||||||
|
/* base + ai->envp->strvec[i] - ai->str_buf */
|
||||||
|
ai->envp.strvec[i] += off;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* replace strings buffer and argv buffer */
|
||||||
|
ai->str_buf = new_strbuf;
|
||||||
|
ai->strings_length = new_strbuf_size;
|
||||||
|
ai->str_buf_size = new_strbuf_size;
|
||||||
|
ai->argv.string_count = new_argc;
|
||||||
|
ai->argv.strvec = (void *)new_argv;
|
||||||
|
ai->argv.strvec_buflen = new_argc;
|
||||||
|
|
||||||
|
ai->argv0_strlen = ow_ai->argv0_strlen;
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *lwp_args_get_argv_0(struct lwp_args_info *ai)
|
||||||
|
{
|
||||||
|
return ai->str_buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
static rt_err_t args_init(struct lwp_args_info *ai, size_t str_buf_size)
|
||||||
|
{
|
||||||
|
void *str_buf;
|
||||||
|
str_buf = rt_malloc(str_buf_size);
|
||||||
|
if (!str_buf)
|
||||||
|
return -RT_ENOMEM;
|
||||||
|
|
||||||
|
memset(ai, 0, sizeof(*ai));
|
||||||
|
|
||||||
|
_strvec_init(&ai->argv);
|
||||||
|
if (!ai->argv.strvec)
|
||||||
|
{
|
||||||
|
rt_free(str_buf);
|
||||||
|
return -RT_ENOMEM;
|
||||||
|
}
|
||||||
|
_strvec_init(&ai->envp);
|
||||||
|
if (!ai->envp.strvec)
|
||||||
|
{
|
||||||
|
rt_free(str_buf);
|
||||||
|
_strvec_detach(&ai->argv);
|
||||||
|
return -RT_ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
ai->str_buf_size = str_buf_size;
|
||||||
|
ai->str_buf = str_buf;
|
||||||
|
return RT_EOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define STR_BUF_DEFAULT_SIZE 2048
|
||||||
|
rt_err_t lwp_args_init(struct lwp_args_info *ai)
|
||||||
|
{
|
||||||
|
return args_init(ai, STR_BUF_DEFAULT_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void lwp_args_detach(struct lwp_args_info *ai)
|
||||||
|
{
|
||||||
|
_strvec_detach(&ai->argv);
|
||||||
|
_strvec_detach(&ai->envp);
|
||||||
|
rt_free(ai->str_buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef ARCH_MM_MMU
|
||||||
|
struct process_aux *lwp_argscopy(struct rt_lwp *lwp, struct lwp_args_info *ai)
|
||||||
|
{
|
||||||
|
int size = sizeof(rt_base_t) * 4; /* store argc, argv_NULL, envp_NULL, aux_NULL */
|
||||||
|
char *str_ua;
|
||||||
|
const char **args_ua;
|
||||||
|
const char **iter;
|
||||||
|
rt_base_t off;
|
||||||
|
struct process_aux_item pa_item;
|
||||||
|
struct process_aux *aux_ua;
|
||||||
|
size_t prot = PROT_READ | PROT_WRITE;
|
||||||
|
size_t flags = MAP_FIXED | MAP_PRIVATE;
|
||||||
|
rt_base_t argc = ai->argv.string_count;
|
||||||
|
rt_base_t envc = ai->envp.string_count;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* counts the bytes to storage the args
|
||||||
|
*/
|
||||||
|
size += argc * sizeof(char *) + envc * sizeof(char *)
|
||||||
|
+ ai->strings_length + sizeof(struct process_aux);
|
||||||
|
|
||||||
|
args_ua = lwp_mmap2(lwp, (void *)(USER_STACK_VEND), size, prot, flags, -1, 0);
|
||||||
|
if (args_ua == RT_NULL)
|
||||||
|
{
|
||||||
|
return RT_NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Put data from args info to user space
|
||||||
|
* argc, argv[], NULL, envp[], NULL, aux[], NULL, strings
|
||||||
|
*/
|
||||||
|
iter = args_ua;
|
||||||
|
|
||||||
|
/* argc */
|
||||||
|
lwp_data_put(lwp, iter++, &argc, sizeof(char *));
|
||||||
|
|
||||||
|
/* strings */
|
||||||
|
str_ua = (char *)((rt_ubase_t)args_ua +
|
||||||
|
(1 + argc + 1 + envc + 1 + AUX_ARRAY_ITEMS_NR * 2 + 1) * sizeof(rt_base_t));
|
||||||
|
lwp_data_put(lwp, str_ua, ai->str_buf, ai->strings_length);
|
||||||
|
|
||||||
|
/* argv */
|
||||||
|
off = str_ua - ai->str_buf;
|
||||||
|
for (size_t i = 0; i < argc; i++)
|
||||||
|
{
|
||||||
|
/* str_ua + ai->argv.strvec[i] - ai->str_buf */
|
||||||
|
ai->argv.strvec[i] += off;
|
||||||
|
}
|
||||||
|
lwp_data_put(lwp, iter, ai->argv.strvec, sizeof(char *) * ai->argv.string_count);
|
||||||
|
iter += ai->argv.string_count;
|
||||||
|
|
||||||
|
/* NULL */
|
||||||
|
lwp_data_set(lwp, iter++, 0, sizeof(char *));
|
||||||
|
|
||||||
|
/* envp */
|
||||||
|
for (size_t i = 0; i < envc; i++)
|
||||||
|
{
|
||||||
|
/* str_ua + ai->envp.strvec[i] - ai->str_buf */
|
||||||
|
ai->envp.strvec[i] += off;
|
||||||
|
}
|
||||||
|
lwp_data_put(lwp, iter, ai->envp.strvec, sizeof(char *) * ai->envp.string_count);
|
||||||
|
iter += ai->envp.string_count;
|
||||||
|
|
||||||
|
/* NULL */
|
||||||
|
lwp_data_set(lwp, iter++, 0, sizeof(char *));
|
||||||
|
|
||||||
|
/* aux */
|
||||||
|
aux_ua = (struct process_aux *)iter;
|
||||||
|
pa_item.key = AT_EXECFN;
|
||||||
|
pa_item.value = (size_t)str_ua;
|
||||||
|
lwp_data_put(lwp, iter, &pa_item, sizeof(pa_item));
|
||||||
|
iter += AUX_ARRAY_ITEMS_NR * 2;
|
||||||
|
|
||||||
|
/* NULL */
|
||||||
|
lwp_data_set(lwp, iter++, 0, sizeof(char *));
|
||||||
|
|
||||||
|
lwp->args = args_ua;
|
||||||
|
|
||||||
|
return aux_ua;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static struct process_aux *lwp_argscopy(struct rt_lwp *lwp, int argc, char **argv, char **envp)
|
||||||
|
{
|
||||||
|
#ifdef ARCH_MM_MMU
|
||||||
|
int size = sizeof(int) * 5; /* store argc, argv, envp, aux, NULL */
|
||||||
|
struct process_aux *aux;
|
||||||
|
#else
|
||||||
|
int size = sizeof(int) * 4; /* store argc, argv, envp, NULL */
|
||||||
|
#endif /* ARCH_MM_MMU */
|
||||||
|
int *args;
|
||||||
|
char *str;
|
||||||
|
char **new_argve;
|
||||||
|
int i;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
for (i = 0; i < argc; i++)
|
||||||
|
{
|
||||||
|
size += (rt_strlen(argv[i]) + 1);
|
||||||
|
}
|
||||||
|
size += (sizeof(int) * argc);
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
if (envp)
|
||||||
|
{
|
||||||
|
while (envp[i] != 0)
|
||||||
|
{
|
||||||
|
size += (rt_strlen(envp[i]) + 1);
|
||||||
|
size += sizeof(int);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef ARCH_MM_MMU
|
||||||
|
/* for aux */
|
||||||
|
size += sizeof(struct process_aux);
|
||||||
|
|
||||||
|
args = (int *)rt_malloc(size);
|
||||||
|
if (args == RT_NULL)
|
||||||
|
{
|
||||||
|
return RT_NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* argc, argv[], 0, envp[], 0 */
|
||||||
|
str = (char *)((size_t)args + (argc + 2 + i + 1 + AUX_ARRAY_ITEMS_NR * 2 + 1) * sizeof(int));
|
||||||
|
#else
|
||||||
|
args = (int *)rt_malloc(size);
|
||||||
|
if (args == RT_NULL)
|
||||||
|
{
|
||||||
|
return RT_NULL;
|
||||||
|
}
|
||||||
|
str = (char*)((int)args + (argc + 2 + i + 1) * sizeof(int));
|
||||||
|
#endif /* ARCH_MM_MMU */
|
||||||
|
|
||||||
|
new_argve = (char **)&args[1];
|
||||||
|
args[0] = argc;
|
||||||
|
|
||||||
|
for (i = 0; i < argc; i++)
|
||||||
|
{
|
||||||
|
len = rt_strlen(argv[i]) + 1;
|
||||||
|
new_argve[i] = str;
|
||||||
|
lwp_memcpy(str, argv[i], len);
|
||||||
|
str += len;
|
||||||
|
}
|
||||||
|
new_argve[i] = 0;
|
||||||
|
i++;
|
||||||
|
|
||||||
|
new_argve[i] = 0;
|
||||||
|
if (envp)
|
||||||
|
{
|
||||||
|
int j;
|
||||||
|
for (j = 0; envp[j] != 0; j++)
|
||||||
|
{
|
||||||
|
len = rt_strlen(envp[j]) + 1;
|
||||||
|
new_argve[i] = str;
|
||||||
|
lwp_memcpy(str, envp[j], len);
|
||||||
|
str += len;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
new_argve[i] = 0;
|
||||||
|
}
|
||||||
|
#ifdef ARCH_MM_MMU
|
||||||
|
/* aux */
|
||||||
|
aux = (struct process_aux *)(new_argve + i);
|
||||||
|
aux->item[0].key = AT_EXECFN;
|
||||||
|
aux->item[0].value = (uint32_t)(size_t)new_argve[0];
|
||||||
|
i += AUX_ARRAY_ITEMS_NR * 2;
|
||||||
|
new_argve[i] = 0;
|
||||||
|
|
||||||
|
lwp->args = args;
|
||||||
|
|
||||||
|
return aux;
|
||||||
|
#else
|
||||||
|
lwp->args = args;
|
||||||
|
lwp->args_length = size;
|
||||||
|
|
||||||
|
return (struct process_aux *)(new_argve + i);
|
||||||
|
#endif /* ARCH_MM_MMU */
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
rt_err_t lwp_args_put(struct lwp_args_info *args, const char **strv_addr, enum lwp_args_type atype)
|
||||||
|
{
|
||||||
|
rt_err_t error;
|
||||||
|
int iter = 0;
|
||||||
|
int len;
|
||||||
|
const char *arg_ptr;
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
if (atype == LWP_ARGS_TYPE_ARG || atype == LWP_ARGS_TYPE_ENVP)
|
||||||
|
{
|
||||||
|
len = lwp_get_from_user(&arg_ptr, strv_addr + iter++, sizeof(char *));
|
||||||
|
if (len != sizeof(char *))
|
||||||
|
{
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
if (arg_ptr == NULL)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
len = lwp_user_strlen(arg_ptr);
|
||||||
|
if (len < 0)
|
||||||
|
{
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
arg_ptr = strv_addr[iter++];
|
||||||
|
if (arg_ptr == NULL)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
len = strlen(arg_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
error = args_append(args, arg_ptr, len, atype);
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Put argument vector to args object
|
||||||
|
*/
|
||||||
|
rt_err_t lwp_args_put_argv(struct lwp_args_info *args, const char **argv_uaddr)
|
||||||
|
{
|
||||||
|
return lwp_args_put(args, argv_uaddr, LWP_ARGS_TYPE_ARG);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Put argument vector to args object
|
||||||
|
*/
|
||||||
|
rt_err_t lwp_args_put_envp(struct lwp_args_info *args, const char **envp_uaddr)
|
||||||
|
{
|
||||||
|
return lwp_args_put(args, envp_uaddr, LWP_ARGS_TYPE_ENVP);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* read words until reach nextline or EOF.
|
||||||
|
* words copied into buffer is never truncated.
|
||||||
|
*/
|
||||||
|
#define READFILE_STAT_EOF_REACHED 0
|
||||||
|
#define READFILE_STAT_NEXTLINE_REACHED 0
|
||||||
|
#define READFILE_STAT_TRUNCATED 1
|
||||||
|
#define READFILE_STAT_CAN_READMORE(stat) (stat)
|
||||||
|
static int _readfile(int fd, size_t maxbytes, char *buffer, int *p_readlen)
|
||||||
|
{
|
||||||
|
int readlen;
|
||||||
|
int stat;
|
||||||
|
char *nlp;
|
||||||
|
|
||||||
|
readlen = read(fd, buffer, maxbytes - 1);
|
||||||
|
if (readlen <= 0)
|
||||||
|
{
|
||||||
|
/* eof, failed */
|
||||||
|
stat = READFILE_STAT_EOF_REACHED;
|
||||||
|
buffer[0] = '\0';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ((nlp = strchr(buffer, '\n')) == NULL)
|
||||||
|
{
|
||||||
|
if (readlen == maxbytes - 1)
|
||||||
|
{
|
||||||
|
int tailing_wordlen = 0;
|
||||||
|
char *cp = buffer + readlen - 1;
|
||||||
|
for (; *cp && *cp != ' ' && *cp != '\t'; cp--, tailing_wordlen++)
|
||||||
|
;
|
||||||
|
if (tailing_wordlen)
|
||||||
|
{
|
||||||
|
lseek(fd, -tailing_wordlen, SEEK_CUR);
|
||||||
|
readlen -= tailing_wordlen;
|
||||||
|
stat = READFILE_STAT_TRUNCATED;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
stat = READFILE_STAT_EOF_REACHED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
stat = READFILE_STAT_EOF_REACHED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
stat = READFILE_STAT_NEXTLINE_REACHED;
|
||||||
|
readlen = nlp - buffer;
|
||||||
|
}
|
||||||
|
buffer[readlen] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p_readlen)
|
||||||
|
*p_readlen = readlen;
|
||||||
|
return stat;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *_find_word(char *cp)
|
||||||
|
{
|
||||||
|
for (; (*cp == ' ') || (*cp == '\t'); cp++)
|
||||||
|
;
|
||||||
|
return cp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *_seperate_and_get_nextword(char *cp)
|
||||||
|
{
|
||||||
|
/* find next whitespace */
|
||||||
|
for (; *cp && (*cp != ' ') && (*cp != '\t'); cp++)
|
||||||
|
;
|
||||||
|
/* seperate words */
|
||||||
|
while ((*cp == ' ') || (*cp == '\t'))
|
||||||
|
{
|
||||||
|
*cp++ = '\0';
|
||||||
|
}
|
||||||
|
return cp;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define INTERP_BUF_SIZE 128
|
||||||
|
rt_err_t lwp_args_load_script(struct lwp_args_info *ai, const char *filename)
|
||||||
|
{
|
||||||
|
rt_err_t error = -1;
|
||||||
|
int fd = -RT_ERROR;
|
||||||
|
int len;
|
||||||
|
int rf_stat;
|
||||||
|
char interp[INTERP_BUF_SIZE];
|
||||||
|
char *cp, *nextword;
|
||||||
|
char script_magic[2];
|
||||||
|
struct lwp_args_info ow_ai = {0};
|
||||||
|
|
||||||
|
fd = open(filename, O_BINARY | O_RDONLY, 0);
|
||||||
|
if (fd < 0)
|
||||||
|
{
|
||||||
|
goto quit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* verify an interpreter script by matching script file magic
|
||||||
|
* eg: #!/bin/sh
|
||||||
|
*/
|
||||||
|
len = read(fd, script_magic, sizeof(script_magic));
|
||||||
|
if (len != 2 || memcmp(script_magic, "#!", sizeof(script_magic)))
|
||||||
|
{
|
||||||
|
goto quit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* setup a new args struct to save script arguments */
|
||||||
|
if (args_init(&ow_ai, INTERP_BUF_SIZE))
|
||||||
|
{
|
||||||
|
goto quit;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
/* read file to buffer (avoid any truncated words in buffer) */
|
||||||
|
rf_stat = _readfile(fd, INTERP_BUF_SIZE, interp, &len);
|
||||||
|
if (len <= 0)
|
||||||
|
{
|
||||||
|
goto quit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* find first word until reaching nil */
|
||||||
|
cp = _find_word(interp);
|
||||||
|
if (*cp == '\0')
|
||||||
|
{
|
||||||
|
if (READFILE_STAT_CAN_READMORE(rf_stat))
|
||||||
|
continue;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
nextword = _seperate_and_get_nextword(cp);
|
||||||
|
args_append(&ow_ai, cp, strlen(cp), LWP_ARGS_TYPE_KARG);
|
||||||
|
cp = nextword;
|
||||||
|
}
|
||||||
|
while (*cp);
|
||||||
|
|
||||||
|
if (READFILE_STAT_CAN_READMORE(rf_stat))
|
||||||
|
continue;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ow_ai.argv.string_count == 0)
|
||||||
|
{
|
||||||
|
goto quit; /* No interpreter name found */
|
||||||
|
}
|
||||||
|
|
||||||
|
args_append(&ow_ai, filename, strlen(filename), LWP_ARGS_TYPE_KARG);
|
||||||
|
error = _args_override_argv0(ai, &ow_ai);
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
goto quit;
|
||||||
|
}
|
||||||
|
|
||||||
|
quit:
|
||||||
|
lwp_args_detach(&ow_ai);
|
||||||
|
if (fd >= 0)
|
||||||
|
{
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
char** lwp_get_command_line_args(struct rt_lwp *lwp)
|
||||||
|
{
|
||||||
|
size_t argc = 0;
|
||||||
|
char** argv = NULL;
|
||||||
|
int ret;
|
||||||
|
size_t i;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
if (lwp)
|
||||||
|
{
|
||||||
|
ret = lwp_data_get(lwp, &argc, lwp->args, sizeof(argc));
|
||||||
|
if (ret == 0)
|
||||||
|
{
|
||||||
|
return RT_NULL;
|
||||||
|
}
|
||||||
|
argv = (char**)rt_malloc((argc + 1) * sizeof(char*));
|
||||||
|
|
||||||
|
if (argv)
|
||||||
|
{
|
||||||
|
for (i = 0; i < argc; i++)
|
||||||
|
{
|
||||||
|
char *argvp = NULL;
|
||||||
|
ret = lwp_data_get(lwp, &argvp, &((char **)lwp->args)[1 + i], sizeof(argvp));
|
||||||
|
if (ret == 0)
|
||||||
|
{
|
||||||
|
lwp_free_command_line_args(argv);
|
||||||
|
return RT_NULL;
|
||||||
|
}
|
||||||
|
len = lwp_user_strlen_ext(lwp, argvp);
|
||||||
|
|
||||||
|
if (len > 0)
|
||||||
|
{
|
||||||
|
argv[i] = (char*)rt_malloc(len + 1);
|
||||||
|
ret = lwp_data_get(lwp, argv[i], argvp, len);
|
||||||
|
if (ret == 0)
|
||||||
|
{
|
||||||
|
lwp_free_command_line_args(argv);
|
||||||
|
return RT_NULL;
|
||||||
|
}
|
||||||
|
argv[i][len] = '\0';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
argv[i] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
argv[argc] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return argv;
|
||||||
|
}
|
||||||
|
|
||||||
|
void lwp_print_envp(struct rt_lwp *lwp)
|
||||||
|
{
|
||||||
|
rt_size_t envp_counts;
|
||||||
|
char **kenvp_array = lwp_get_envp(lwp, &envp_counts);
|
||||||
|
if (kenvp_array)
|
||||||
|
{
|
||||||
|
rt_kprintf("envp_counts: %d\n", envp_counts);
|
||||||
|
for (size_t i = 0; i < envp_counts; i++)
|
||||||
|
{
|
||||||
|
rt_kprintf("envp[%d]: %s\n", i, kenvp_array[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lwp_free_command_line_args(kenvp_array);
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
|
||||||
|
char** lwp_get_envp(struct rt_lwp *lwp, rt_size_t *penvp_counts)
|
||||||
|
{
|
||||||
|
int ret, len;
|
||||||
|
rt_base_t argc;
|
||||||
|
char **p_kenvp = RT_NULL;
|
||||||
|
char *envp, **p_envp;
|
||||||
|
size_t envp_counts = 0;
|
||||||
|
|
||||||
|
if (lwp)
|
||||||
|
{
|
||||||
|
ret = lwp_data_get(lwp, &argc, lwp->args, sizeof(argc));
|
||||||
|
if (ret == 0)
|
||||||
|
{
|
||||||
|
return RT_NULL;
|
||||||
|
}
|
||||||
|
p_envp = (char **)lwp->args + 1 + argc + 1;
|
||||||
|
|
||||||
|
/* counts envp */
|
||||||
|
while (lwp_data_get(lwp, &envp, p_envp, sizeof(void *)) == sizeof(void *)
|
||||||
|
&& envp != NULL)
|
||||||
|
{
|
||||||
|
p_envp++;
|
||||||
|
envp_counts++;
|
||||||
|
}
|
||||||
|
|
||||||
|
p_kenvp = (char **)rt_malloc((envp_counts + 1) * sizeof(char *));
|
||||||
|
if (p_kenvp)
|
||||||
|
{
|
||||||
|
/* copy env from envp array */
|
||||||
|
p_envp = (char **)lwp->args + 1 + argc + 1;
|
||||||
|
for (size_t i = 0; i < envp_counts; i++)
|
||||||
|
{
|
||||||
|
ret = lwp_data_get(lwp, &envp, &p_envp[i], sizeof(char *));
|
||||||
|
if (ret != sizeof(char **))
|
||||||
|
{
|
||||||
|
lwp_free_command_line_args(p_kenvp);
|
||||||
|
return RT_NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
len = lwp_user_strlen_ext(lwp, envp);
|
||||||
|
if (len > 0)
|
||||||
|
{
|
||||||
|
p_kenvp[i] = (char*)rt_malloc(len + 1);
|
||||||
|
ret = lwp_data_get(lwp, p_kenvp[i], envp, len + 1);
|
||||||
|
if (ret != len + 1)
|
||||||
|
{
|
||||||
|
lwp_free_command_line_args(p_kenvp);
|
||||||
|
return RT_NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
p_kenvp[i] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (penvp_counts)
|
||||||
|
*penvp_counts = envp_counts;
|
||||||
|
p_kenvp[envp_counts] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return p_kenvp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void lwp_free_command_line_args(char** argv)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
if (argv)
|
||||||
|
{
|
||||||
|
for (i = 0; argv[i]; i++)
|
||||||
|
{
|
||||||
|
rt_free(argv[i]);
|
||||||
|
}
|
||||||
|
rt_free(argv);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2006-2024, RT-Thread Development Team
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Change Logs:
|
||||||
|
* Date Author Notes
|
||||||
|
* 2024-01-12 Shell separate argv, envp, aux processing from execve(2).
|
||||||
|
* Bugs fix for script arguments processing.
|
||||||
|
*/
|
||||||
|
#ifndef __LWP_ARGV_H__
|
||||||
|
#define __LWP_ARGV_H__
|
||||||
|
|
||||||
|
#include <rtthread.h>
|
||||||
|
|
||||||
|
struct rt_lwp;
|
||||||
|
|
||||||
|
enum lwp_args_type {
|
||||||
|
LWP_ARGS_TYPE_ARG,
|
||||||
|
LWP_ARGS_TYPE_KARG,
|
||||||
|
LWP_ARGS_TYPE_ENVP,
|
||||||
|
LWP_ARGS_TYPE_KENVP,
|
||||||
|
LWP_ARGS_TYPE_NULLPTR
|
||||||
|
};
|
||||||
|
|
||||||
|
struct lwp_string_vector
|
||||||
|
{
|
||||||
|
const char **strvec;
|
||||||
|
rt_uint32_t strvec_buflen;
|
||||||
|
rt_uint32_t string_count;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct lwp_args_info
|
||||||
|
{
|
||||||
|
int argv0_strlen;
|
||||||
|
int strings_length;
|
||||||
|
int str_buf_size;
|
||||||
|
|
||||||
|
char *str_buf;
|
||||||
|
struct lwp_string_vector argv;
|
||||||
|
struct lwp_string_vector envp;
|
||||||
|
};
|
||||||
|
|
||||||
|
rt_err_t lwp_args_init(struct lwp_args_info *ai);
|
||||||
|
void lwp_args_detach(struct lwp_args_info *ai);
|
||||||
|
struct process_aux *lwp_argscopy(struct rt_lwp *lwp, struct lwp_args_info *args_info);;
|
||||||
|
rt_err_t lwp_args_put(struct lwp_args_info *args, const char **strv_addr, enum lwp_args_type atype);
|
||||||
|
rt_err_t lwp_args_put_argv(struct lwp_args_info *args, const char **argv_uaddr);
|
||||||
|
rt_err_t lwp_args_put_envp(struct lwp_args_info *args, const char **envp_uaddr);
|
||||||
|
rt_err_t lwp_args_load_script(struct lwp_args_info *args, const char *filename);
|
||||||
|
const char *lwp_args_get_argv_0(struct lwp_args_info *ai);
|
||||||
|
char** lwp_get_envp(struct rt_lwp *lwp, rt_size_t *penvp_counts);
|
||||||
|
void lwp_print_envp(struct rt_lwp *lwp);
|
||||||
|
|
||||||
|
char** lwp_get_command_line_args(struct rt_lwp *lwp);
|
||||||
|
void lwp_free_command_line_args(char** argv);
|
||||||
|
|
||||||
|
#endif /* __LWP_ARGV_H__ */
|
|
@ -50,8 +50,10 @@
|
||||||
#define ELF_AUX_ENT(aux, id, val) \
|
#define ELF_AUX_ENT(aux, id, val) \
|
||||||
do \
|
do \
|
||||||
{ \
|
{ \
|
||||||
*aux++ = id; \
|
rt_base_t a = id; \
|
||||||
*aux++ = val; \
|
lwp_data_put(lwp, aux++, &a, sizeof(rt_ubase_t)); \
|
||||||
|
a = val; \
|
||||||
|
lwp_data_put(lwp, aux++, &a, sizeof(rt_ubase_t)); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
|
@ -571,6 +573,7 @@ static int elf_aux_fill(elf_load_info_t *load_info)
|
||||||
uint32_t random_value = rt_tick_get();
|
uint32_t random_value = rt_tick_get();
|
||||||
size_t prot = PROT_READ | PROT_WRITE;
|
size_t prot = PROT_READ | PROT_WRITE;
|
||||||
size_t flags = MAP_PRIVATE;
|
size_t flags = MAP_PRIVATE;
|
||||||
|
rt_lwp_t lwp = load_info->lwp;
|
||||||
void *va;
|
void *va;
|
||||||
|
|
||||||
if (!aux)
|
if (!aux)
|
||||||
|
@ -581,7 +584,7 @@ static int elf_aux_fill(elf_load_info_t *load_info)
|
||||||
aux_info = (elf_addr_t *)aux->item;
|
aux_info = (elf_addr_t *)aux->item;
|
||||||
ELF_AUX_ENT(aux_info, AT_PAGESZ, ARCH_PAGE_SIZE);
|
ELF_AUX_ENT(aux_info, AT_PAGESZ, ARCH_PAGE_SIZE);
|
||||||
|
|
||||||
va = lwp_mmap2(load_info->lwp, (void *)(USER_VADDR_TOP - ARCH_PAGE_SIZE * 2), ARCH_PAGE_SIZE, prot, flags, -1, 0);
|
va = lwp_mmap2(lwp, (void *)(USER_VADDR_TOP - ARCH_PAGE_SIZE * 2), ARCH_PAGE_SIZE, prot, flags, -1, 0);
|
||||||
if (!va)
|
if (!va)
|
||||||
{
|
{
|
||||||
LOG_E("lwp map user failed!");
|
LOG_E("lwp map user failed!");
|
||||||
|
@ -604,10 +607,6 @@ static int elf_aux_fill(elf_load_info_t *load_info)
|
||||||
ELF_AUX_ENT(aux_info, AT_CLKTCK, 0);
|
ELF_AUX_ENT(aux_info, AT_CLKTCK, 0);
|
||||||
ELF_AUX_ENT(aux_info, AT_SECURE, 0);
|
ELF_AUX_ENT(aux_info, AT_SECURE, 0);
|
||||||
|
|
||||||
#ifdef ARCH_MM_MMU
|
|
||||||
rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, aux, sizeof(*aux));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -757,7 +756,7 @@ OUT:
|
||||||
}
|
}
|
||||||
|
|
||||||
int lwp_load(const char *filename, struct rt_lwp *lwp, uint8_t *load_addr, size_t addr_size,
|
int lwp_load(const char *filename, struct rt_lwp *lwp, uint8_t *load_addr, size_t addr_size,
|
||||||
struct process_aux *aux)
|
struct process_aux *aux_ua)
|
||||||
{
|
{
|
||||||
elf_load_info_t load_info = { 0 };
|
elf_load_info_t load_info = { 0 };
|
||||||
int len;
|
int len;
|
||||||
|
@ -789,7 +788,7 @@ int lwp_load(const char *filename, struct rt_lwp *lwp, uint8_t *load_addr, size_
|
||||||
}
|
}
|
||||||
|
|
||||||
load_info.lwp = lwp;
|
load_info.lwp = lwp;
|
||||||
load_info.aux = aux;
|
load_info.aux = aux_ua;
|
||||||
|
|
||||||
load_info.exec_info.fd = ELF_INVALID_FD;
|
load_info.exec_info.fd = ELF_INVALID_FD;
|
||||||
load_info.interp_info.fd = ELF_INVALID_FD;
|
load_info.interp_info.fd = ELF_INVALID_FD;
|
||||||
|
|
|
@ -186,6 +186,4 @@ rt_err_t lwp_critical_exit(struct rt_lwp *lwp);
|
||||||
#define LWP_RETURN(name) {RT_ASSERT(name != _LWP_UNINITIALIZED_RC);return name;}
|
#define LWP_RETURN(name) {RT_ASSERT(name != _LWP_UNINITIALIZED_RC);return name;}
|
||||||
#endif /* LWP_DEBUG */
|
#endif /* LWP_DEBUG */
|
||||||
|
|
||||||
int load_ldso(struct rt_lwp *lwp, char *exec_name, char *const argv[], char *const envp[]);
|
|
||||||
|
|
||||||
#endif /* __LWP_INTERNAL_H__ */
|
#endif /* __LWP_INTERNAL_H__ */
|
||||||
|
|
|
@ -2162,10 +2162,6 @@ rt_weak sysret_t sys_vfork(void)
|
||||||
return sys_fork();
|
return sys_fork();
|
||||||
}
|
}
|
||||||
|
|
||||||
struct process_aux *lwp_argscopy(struct rt_lwp *lwp, int argc, char **argv, char **envp);
|
|
||||||
int lwp_load(const char *filename, struct rt_lwp *lwp, uint8_t *load_addr, size_t addr_size, struct process_aux *aux);
|
|
||||||
void lwp_user_obj_free(struct rt_lwp *lwp);
|
|
||||||
|
|
||||||
#define _swap_lwp_data(lwp_used, lwp_new, type, member) \
|
#define _swap_lwp_data(lwp_used, lwp_new, type, member) \
|
||||||
do {\
|
do {\
|
||||||
type tmp;\
|
type tmp;\
|
||||||
|
@ -2174,339 +2170,17 @@ void lwp_user_obj_free(struct rt_lwp *lwp);
|
||||||
lwp_new->member = tmp;\
|
lwp_new->member = tmp;\
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
static char *_insert_args(int new_argc, char *new_argv[], struct lwp_args_info *args)
|
|
||||||
{
|
|
||||||
void *page = NULL;
|
|
||||||
int err = 0;
|
|
||||||
char **nargv;
|
|
||||||
char **nenvp;
|
|
||||||
char *p;
|
|
||||||
int i, len;
|
|
||||||
int nsize;
|
|
||||||
|
|
||||||
if (new_argc == 0)
|
|
||||||
{
|
|
||||||
goto quit;
|
|
||||||
}
|
|
||||||
page = rt_pages_alloc_ext(0, PAGE_ANY_AVAILABLE); /* 1 page */
|
|
||||||
if (!page)
|
|
||||||
{
|
|
||||||
goto quit;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsize = new_argc * sizeof(char *);
|
|
||||||
for (i = 0; i < new_argc; i++)
|
|
||||||
{
|
|
||||||
nsize += lwp_strlen(lwp_self(), new_argv[i]) + 1;
|
|
||||||
}
|
|
||||||
if (nsize + args->size > ARCH_PAGE_SIZE)
|
|
||||||
{
|
|
||||||
err = 1;
|
|
||||||
goto quit;
|
|
||||||
}
|
|
||||||
nargv = (char **)page;
|
|
||||||
nenvp = nargv + args->argc + new_argc + 1;
|
|
||||||
p = (char *)(nenvp + args->envc + 1);
|
|
||||||
/* insert argv */
|
|
||||||
for (i = 0; i < new_argc; i++)
|
|
||||||
{
|
|
||||||
nargv[i] = p;
|
|
||||||
len = lwp_strlen(lwp_self(), new_argv[i]) + 1;
|
|
||||||
lwp_memcpy(p, new_argv[i], len);
|
|
||||||
p += len;
|
|
||||||
}
|
|
||||||
/* copy argv */
|
|
||||||
nargv += new_argc;
|
|
||||||
for (i = 0; i < args->argc; i++)
|
|
||||||
{
|
|
||||||
nargv[i] = p;
|
|
||||||
len = lwp_strlen(lwp_self(), args->argv[i]) + 1;
|
|
||||||
lwp_memcpy(p, args->argv[i], len);
|
|
||||||
p += len;
|
|
||||||
}
|
|
||||||
nargv[i] = NULL;
|
|
||||||
/* copy envp */
|
|
||||||
for (i = 0; i < args->envc; i++)
|
|
||||||
{
|
|
||||||
nenvp[i] = p;
|
|
||||||
len = lwp_strlen(lwp_self(), args->envp[i]) + 1;
|
|
||||||
lwp_memcpy(p, args->envp[i], len);
|
|
||||||
p += len;
|
|
||||||
}
|
|
||||||
nenvp[i] = NULL;
|
|
||||||
|
|
||||||
/* update args */
|
|
||||||
args->argv = (char **)page;
|
|
||||||
args->argc = args->argc + new_argc;
|
|
||||||
args->envp = args->argv + args->argc + 1;
|
|
||||||
/* args->envc no change */
|
|
||||||
args->size = args->size + nsize;
|
|
||||||
|
|
||||||
quit:
|
|
||||||
if (err && page)
|
|
||||||
{
|
|
||||||
rt_pages_free(page, 0);
|
|
||||||
page = NULL;
|
|
||||||
}
|
|
||||||
return page;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define INTERP_BUF_SIZE 128
|
|
||||||
static char *_load_script(const char *filename, void *old_page, struct lwp_args_info *args)
|
|
||||||
{
|
|
||||||
char *new_page = NULL;
|
|
||||||
int fd = -RT_ERROR;
|
|
||||||
int len;
|
|
||||||
char interp[INTERP_BUF_SIZE];
|
|
||||||
char *cp;
|
|
||||||
char *i_name;
|
|
||||||
char *i_arg;
|
|
||||||
|
|
||||||
fd = open(filename, O_BINARY | O_RDONLY, 0);
|
|
||||||
if (fd < 0)
|
|
||||||
{
|
|
||||||
goto quit;
|
|
||||||
}
|
|
||||||
len = read(fd, interp, INTERP_BUF_SIZE);
|
|
||||||
if (len < 2)
|
|
||||||
{
|
|
||||||
goto quit;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* match find file header the first line.
|
|
||||||
* eg: #!/bin/sh
|
|
||||||
*/
|
|
||||||
if ((interp[0] != '#') || (interp[1] != '!'))
|
|
||||||
{
|
|
||||||
goto quit;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (len == INTERP_BUF_SIZE)
|
|
||||||
{
|
|
||||||
len--;
|
|
||||||
}
|
|
||||||
interp[len] = '\0';
|
|
||||||
|
|
||||||
if ((cp = strchr(interp, '\n')) == NULL)
|
|
||||||
{
|
|
||||||
cp = interp + INTERP_BUF_SIZE - 1;
|
|
||||||
}
|
|
||||||
*cp = '\0';
|
|
||||||
while (cp > interp)
|
|
||||||
{
|
|
||||||
cp--;
|
|
||||||
if ((*cp == ' ') || (*cp == '\t'))
|
|
||||||
{
|
|
||||||
*cp = '\0';
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (cp = interp + 2; (*cp == ' ') || (*cp == '\t'); cp++)
|
|
||||||
{
|
|
||||||
/* nothing */
|
|
||||||
}
|
|
||||||
if (*cp == '\0')
|
|
||||||
{
|
|
||||||
goto quit; /* No interpreter name found */
|
|
||||||
}
|
|
||||||
i_name = cp;
|
|
||||||
i_arg = NULL;
|
|
||||||
for (; *cp && (*cp != ' ') && (*cp != '\t'); cp++)
|
|
||||||
{
|
|
||||||
/* nothing */
|
|
||||||
}
|
|
||||||
while ((*cp == ' ') || (*cp == '\t'))
|
|
||||||
{
|
|
||||||
*cp++ = '\0';
|
|
||||||
}
|
|
||||||
if (*cp)
|
|
||||||
{
|
|
||||||
i_arg = cp;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i_arg)
|
|
||||||
{
|
|
||||||
new_page = _insert_args(1, &i_arg, args);
|
|
||||||
if (!new_page)
|
|
||||||
{
|
|
||||||
goto quit;
|
|
||||||
}
|
|
||||||
rt_pages_free(old_page, 0);
|
|
||||||
old_page = new_page;
|
|
||||||
}
|
|
||||||
new_page = _insert_args(1, &i_name, args);
|
|
||||||
if (!new_page)
|
|
||||||
{
|
|
||||||
goto quit;
|
|
||||||
}
|
|
||||||
rt_pages_free(old_page, 0);
|
|
||||||
|
|
||||||
quit:
|
|
||||||
if (fd >= 0)
|
|
||||||
{
|
|
||||||
close(fd);
|
|
||||||
}
|
|
||||||
return new_page;
|
|
||||||
}
|
|
||||||
|
|
||||||
int load_ldso(struct rt_lwp *lwp, char *exec_name, char *const argv[], char *const envp[])
|
|
||||||
{
|
|
||||||
int ret = -1;
|
|
||||||
int i;
|
|
||||||
void *page;
|
|
||||||
void *new_page;
|
|
||||||
int argc = 0;
|
|
||||||
int envc = 0;
|
|
||||||
int size;
|
|
||||||
char **kargv;
|
|
||||||
char **kenvp;
|
|
||||||
size_t len;
|
|
||||||
char *p;
|
|
||||||
char *i_arg;
|
|
||||||
struct lwp_args_info args_info;
|
|
||||||
struct process_aux *aux;
|
|
||||||
|
|
||||||
size = sizeof(char *);
|
|
||||||
if (argv)
|
|
||||||
{
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
if (!argv[argc])
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
len = lwp_strlen(lwp, (const char *)argv[argc]);
|
|
||||||
size += sizeof(char *) + len + 1;
|
|
||||||
argc++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (envp)
|
|
||||||
{
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
if (!envp[envc])
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
len = lwp_strlen(lwp, (const char *)envp[envc]);
|
|
||||||
size += sizeof(char *) + len + 1;
|
|
||||||
envc++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
page = rt_pages_alloc_ext(0, PAGE_ANY_AVAILABLE); /* 1 page */
|
|
||||||
if (!page)
|
|
||||||
{
|
|
||||||
SET_ERRNO(ENOMEM);
|
|
||||||
goto quit;
|
|
||||||
}
|
|
||||||
kargv = (char **)page;
|
|
||||||
kenvp = kargv + argc + 1;
|
|
||||||
p = (char *)(kenvp + envc + 1);
|
|
||||||
/* copy argv */
|
|
||||||
if (argv)
|
|
||||||
{
|
|
||||||
for (i = 0; i < argc; i++)
|
|
||||||
{
|
|
||||||
kargv[i] = p;
|
|
||||||
len = lwp_strlen(lwp, argv[i]) + 1;
|
|
||||||
lwp_memcpy(p, argv[i], len);
|
|
||||||
p += len;
|
|
||||||
}
|
|
||||||
kargv[i] = NULL;
|
|
||||||
}
|
|
||||||
/* copy envp */
|
|
||||||
if (envp)
|
|
||||||
{
|
|
||||||
for (i = 0; i < envc; i++)
|
|
||||||
{
|
|
||||||
kenvp[i] = p;
|
|
||||||
len = lwp_strlen(lwp, envp[i]) + 1;
|
|
||||||
lwp_memcpy(p, envp[i], len);
|
|
||||||
p += len;
|
|
||||||
}
|
|
||||||
kenvp[i] = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
args_info.argc = argc;
|
|
||||||
args_info.argv = kargv;
|
|
||||||
args_info.envc = envc;
|
|
||||||
args_info.envp = kenvp;
|
|
||||||
args_info.size = size;
|
|
||||||
|
|
||||||
new_page = _insert_args(1, &exec_name, &args_info);
|
|
||||||
if (!new_page)
|
|
||||||
{
|
|
||||||
SET_ERRNO(ENOMEM);
|
|
||||||
goto quit;
|
|
||||||
}
|
|
||||||
rt_pages_free(page, 0);
|
|
||||||
page = new_page;
|
|
||||||
|
|
||||||
i_arg = "-e";
|
|
||||||
new_page = _insert_args(1, &i_arg, &args_info);
|
|
||||||
if (!new_page)
|
|
||||||
{
|
|
||||||
SET_ERRNO(ENOMEM);
|
|
||||||
goto quit;
|
|
||||||
}
|
|
||||||
rt_pages_free(page, 0);
|
|
||||||
page = new_page;
|
|
||||||
|
|
||||||
i_arg = "ld.so";
|
|
||||||
new_page = _insert_args(1, &i_arg, &args_info);
|
|
||||||
if (!new_page)
|
|
||||||
{
|
|
||||||
SET_ERRNO(ENOMEM);
|
|
||||||
goto quit;
|
|
||||||
}
|
|
||||||
rt_pages_free(page, 0);
|
|
||||||
page = new_page;
|
|
||||||
|
|
||||||
if ((aux = lwp_argscopy(lwp, args_info.argc, args_info.argv, args_info.envp)) == NULL)
|
|
||||||
{
|
|
||||||
SET_ERRNO(ENOMEM);
|
|
||||||
goto quit;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = lwp_load("/lib/ld.so", lwp, RT_NULL, 0, aux);
|
|
||||||
|
|
||||||
rt_strncpy(lwp->cmd, exec_name, RT_NAME_MAX - 1);
|
|
||||||
quit:
|
|
||||||
if (page)
|
|
||||||
{
|
|
||||||
rt_pages_free(page, 0);
|
|
||||||
}
|
|
||||||
return (ret < 0 ? GET_ERRNO() : ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
sysret_t sys_execve(const char *path, char *const argv[], char *const envp[])
|
sysret_t sys_execve(const char *path, char *const argv[], char *const envp[])
|
||||||
{
|
{
|
||||||
int ret = -1;
|
int error = -1;
|
||||||
int argc = 0;
|
|
||||||
int envc = 0;
|
|
||||||
void *page = NULL;
|
|
||||||
void *new_page;
|
|
||||||
int size = 0;
|
|
||||||
size_t len;
|
size_t len;
|
||||||
char **kargv;
|
|
||||||
char **kenvp;
|
|
||||||
char *p;
|
|
||||||
struct rt_lwp *new_lwp = NULL;
|
struct rt_lwp *new_lwp = NULL;
|
||||||
struct rt_lwp *lwp;
|
struct rt_lwp *lwp;
|
||||||
int uni_thread;
|
int uni_thread;
|
||||||
rt_thread_t thread;
|
rt_thread_t thread;
|
||||||
struct process_aux *aux;
|
struct process_aux *aux;
|
||||||
int i;
|
|
||||||
struct lwp_args_info args_info;
|
struct lwp_args_info args_info;
|
||||||
|
char *kpath = RT_NULL;
|
||||||
if (access(path, X_OK) != 0)
|
|
||||||
{
|
|
||||||
return -EACCES;
|
|
||||||
}
|
|
||||||
|
|
||||||
lwp = lwp_self();
|
lwp = lwp_self();
|
||||||
thread = rt_thread_self();
|
thread = rt_thread_self();
|
||||||
|
@ -2525,163 +2199,108 @@ sysret_t sys_execve(const char *path, char *const argv[], char *const envp[])
|
||||||
|
|
||||||
if (!uni_thread)
|
if (!uni_thread)
|
||||||
{
|
{
|
||||||
SET_ERRNO(EINVAL);
|
return -EINVAL;
|
||||||
goto quit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
len = lwp_user_strlen(path);
|
len = lwp_user_strlen(path);
|
||||||
if (len <= 0)
|
if (len <= 0)
|
||||||
{
|
{
|
||||||
SET_ERRNO(EFAULT);
|
return -EFAULT;
|
||||||
goto quit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size += sizeof(char *);
|
kpath = rt_malloc(len + 1);
|
||||||
if (argv)
|
if (!kpath)
|
||||||
{
|
{
|
||||||
while (1)
|
return -ENOMEM;
|
||||||
{
|
}
|
||||||
if (!lwp_user_accessable((void *)(argv + argc), sizeof(char *)))
|
|
||||||
{
|
if (lwp_get_from_user(kpath, (void *)path, len) != len)
|
||||||
SET_ERRNO(EFAULT);
|
{
|
||||||
goto quit;
|
rt_free(kpath);
|
||||||
}
|
return -EFAULT;
|
||||||
if (!argv[argc])
|
}
|
||||||
{
|
kpath[len] = '\0';
|
||||||
break;
|
|
||||||
}
|
if (access(kpath, X_OK) != 0)
|
||||||
len = lwp_user_strlen((const char *)argv[argc]);
|
{
|
||||||
if (len < 0)
|
rt_free(kpath);
|
||||||
{
|
return -EACCES;
|
||||||
SET_ERRNO(EFAULT);
|
}
|
||||||
goto quit;
|
|
||||||
}
|
/* setup args */
|
||||||
size += sizeof(char *) + len + 1;
|
error = lwp_args_init(&args_info);
|
||||||
argc++;
|
if (error)
|
||||||
}
|
{
|
||||||
}
|
rt_free(kpath);
|
||||||
size += sizeof(char *);
|
return -ENOMEM;
|
||||||
if (envp)
|
|
||||||
{
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
if (!lwp_user_accessable((void *)(envp + envc), sizeof(char *)))
|
|
||||||
{
|
|
||||||
SET_ERRNO(EFAULT);
|
|
||||||
goto quit;
|
|
||||||
}
|
|
||||||
if (!envp[envc])
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
len = lwp_user_strlen((const char *)envp[envc]);
|
|
||||||
if (len < 0)
|
|
||||||
{
|
|
||||||
SET_ERRNO(EFAULT);
|
|
||||||
goto quit;
|
|
||||||
}
|
|
||||||
size += sizeof(char *) + len + 1;
|
|
||||||
envc++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (size > ARCH_PAGE_SIZE)
|
|
||||||
{
|
|
||||||
SET_ERRNO(EINVAL);
|
|
||||||
goto quit;
|
|
||||||
}
|
|
||||||
page = rt_pages_alloc_ext(0, PAGE_ANY_AVAILABLE); /* 1 page */
|
|
||||||
if (!page)
|
|
||||||
{
|
|
||||||
SET_ERRNO(ENOMEM);
|
|
||||||
goto quit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
kargv = (char **)page;
|
|
||||||
kenvp = kargv + argc + 1;
|
|
||||||
p = (char *)(kenvp + envc + 1);
|
|
||||||
/* copy argv */
|
|
||||||
if (argv)
|
if (argv)
|
||||||
{
|
{
|
||||||
for (i = 0; i < argc; i++)
|
error = lwp_args_put_argv(&args_info, (void *)argv);
|
||||||
|
if (error)
|
||||||
{
|
{
|
||||||
kargv[i] = p;
|
error = -EFAULT;
|
||||||
len = lwp_user_strlen(argv[i]) + 1;
|
goto quit;
|
||||||
lwp_memcpy(p, argv[i], len);
|
|
||||||
p += len;
|
|
||||||
}
|
}
|
||||||
kargv[i] = NULL;
|
|
||||||
}
|
}
|
||||||
/* copy envp */
|
|
||||||
if (envp)
|
if (envp)
|
||||||
{
|
{
|
||||||
for (i = 0; i < envc; i++)
|
error = lwp_args_put_envp(&args_info, (void *)envp);
|
||||||
|
if (error)
|
||||||
{
|
{
|
||||||
kenvp[i] = p;
|
error = -EFAULT;
|
||||||
len = lwp_user_strlen(envp[i]) + 1;
|
goto quit;
|
||||||
lwp_memcpy(p, envp[i], len);
|
|
||||||
p += len;
|
|
||||||
}
|
}
|
||||||
kenvp[i] = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* alloc new lwp to operation */
|
/* alloc new lwp to operation */
|
||||||
new_lwp = lwp_create(LWP_CREATE_FLAG_NONE);
|
new_lwp = lwp_create(LWP_CREATE_FLAG_NONE);
|
||||||
if (!new_lwp)
|
if (!new_lwp)
|
||||||
{
|
{
|
||||||
SET_ERRNO(ENOMEM);
|
error = -ENOMEM;
|
||||||
goto quit;
|
goto quit;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = lwp_user_space_init(new_lwp, 0);
|
error = lwp_user_space_init(new_lwp, 0);
|
||||||
if (ret != 0)
|
if (error != 0)
|
||||||
{
|
{
|
||||||
SET_ERRNO(ENOMEM);
|
error = -ENOMEM;
|
||||||
goto quit;
|
goto quit;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* file is a script ? */
|
/* file is a script ? */
|
||||||
args_info.argc = argc;
|
path = kpath;
|
||||||
args_info.argv = kargv;
|
|
||||||
args_info.envc = envc;
|
|
||||||
args_info.envp = kenvp;
|
|
||||||
args_info.size = size;
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
new_page = _load_script(path, page, &args_info);
|
error = lwp_args_load_script(&args_info, path);
|
||||||
if (!new_page)
|
if (error != 0)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
path = lwp_args_get_argv_0(&args_info);
|
||||||
page = new_page;
|
|
||||||
path = args_info.argv[0];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* now load elf */
|
/* now load elf */
|
||||||
if ((aux = lwp_argscopy(new_lwp, args_info.argc, args_info.argv, args_info.envp)) == NULL)
|
if ((aux = lwp_argscopy(new_lwp, &args_info)) == NULL)
|
||||||
{
|
{
|
||||||
SET_ERRNO(ENOMEM);
|
error = -ENOMEM;
|
||||||
goto quit;
|
goto quit;
|
||||||
}
|
}
|
||||||
ret = lwp_load(path, new_lwp, RT_NULL, 0, aux);
|
error = lwp_load(path, new_lwp, RT_NULL, 0, aux);
|
||||||
if (ret == 1)
|
if (error == RT_EOK)
|
||||||
{
|
|
||||||
/* dynamic */
|
|
||||||
lwp_unmap_user(new_lwp, (void *)(USER_VADDR_TOP - ARCH_PAGE_SIZE));
|
|
||||||
ret = load_ldso(new_lwp, (char *)path, args_info.argv, args_info.envp);
|
|
||||||
}
|
|
||||||
if (ret == RT_EOK)
|
|
||||||
{
|
{
|
||||||
int off = 0;
|
int off = 0;
|
||||||
int last_backslash = 0;
|
int last_backslash = 0;
|
||||||
char *run_name = args_info.argv[0];
|
|
||||||
|
|
||||||
/* clear all user objects */
|
/* clear all user objects */
|
||||||
lwp_user_object_clear(lwp);
|
lwp_user_object_clear(lwp);
|
||||||
|
|
||||||
/* find last \ or / */
|
/* find last \ or / to get base name */
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
char c = run_name[off++];
|
char c = path[off++];
|
||||||
|
|
||||||
if (c == '\0')
|
if (c == '\0')
|
||||||
{
|
{
|
||||||
|
@ -2700,13 +2319,11 @@ sysret_t sys_execve(const char *path, char *const argv[], char *const envp[])
|
||||||
*/
|
*/
|
||||||
RT_ASSERT(rt_list_entry(lwp->t_grp.prev, struct rt_thread, sibling) == thread);
|
RT_ASSERT(rt_list_entry(lwp->t_grp.prev, struct rt_thread, sibling) == thread);
|
||||||
|
|
||||||
strncpy(thread->parent.name, run_name + last_backslash, RT_NAME_MAX - 1);
|
strncpy(thread->parent.name, path + last_backslash, RT_NAME_MAX - 1);
|
||||||
strncpy(lwp->cmd, new_lwp->cmd, RT_NAME_MAX);
|
strncpy(lwp->cmd, new_lwp->cmd, RT_NAME_MAX);
|
||||||
rt_free(lwp->exe_file);
|
rt_free(lwp->exe_file);
|
||||||
lwp->exe_file = strndup(new_lwp->exe_file, DFS_PATH_MAX);
|
lwp->exe_file = strndup(new_lwp->exe_file, DFS_PATH_MAX);
|
||||||
|
|
||||||
rt_pages_free(page, 0);
|
|
||||||
|
|
||||||
#ifdef ARCH_MM_MMU
|
#ifdef ARCH_MM_MMU
|
||||||
_swap_lwp_data(lwp, new_lwp, struct rt_aspace *, aspace);
|
_swap_lwp_data(lwp, new_lwp, struct rt_aspace *, aspace);
|
||||||
|
|
||||||
|
@ -2737,17 +2354,18 @@ sysret_t sys_execve(const char *path, char *const argv[], char *const envp[])
|
||||||
(char *)thread->stack_addr + thread->stack_size);
|
(char *)thread->stack_addr + thread->stack_size);
|
||||||
/* never reach here */
|
/* never reach here */
|
||||||
}
|
}
|
||||||
return -EINVAL;
|
error = -EINVAL;
|
||||||
quit:
|
quit:
|
||||||
if (page)
|
if (kpath)
|
||||||
{
|
{
|
||||||
rt_pages_free(page, 0);
|
rt_free(kpath);
|
||||||
}
|
}
|
||||||
|
lwp_args_detach(&args_info);
|
||||||
if (new_lwp)
|
if (new_lwp)
|
||||||
{
|
{
|
||||||
lwp_ref_dec(new_lwp);
|
lwp_ref_dec(new_lwp);
|
||||||
}
|
}
|
||||||
return (ret < 0 ? GET_ERRNO() : ret);
|
return error;
|
||||||
}
|
}
|
||||||
#endif /* ARCH_MM_MMU */
|
#endif /* ARCH_MM_MMU */
|
||||||
|
|
||||||
|
|
|
@ -991,71 +991,4 @@ size_t lwp_strlen(struct rt_lwp *lwp, const char *s)
|
||||||
return strlen(s);
|
return strlen(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
char** lwp_get_command_line_args(struct rt_lwp *lwp)
|
|
||||||
{
|
|
||||||
size_t argc = 0;
|
|
||||||
char** argv = NULL;
|
|
||||||
int ret;
|
|
||||||
size_t i;
|
|
||||||
size_t len;
|
|
||||||
|
|
||||||
if (lwp)
|
|
||||||
{
|
|
||||||
ret = lwp_data_get(lwp, &argc, lwp->args, sizeof(argc));
|
|
||||||
if (ret == 0)
|
|
||||||
{
|
|
||||||
return RT_NULL;
|
|
||||||
}
|
|
||||||
argv = (char**)rt_malloc((argc + 1) * sizeof(char*));
|
|
||||||
|
|
||||||
if (argv)
|
|
||||||
{
|
|
||||||
for (i = 0; i < argc; i++)
|
|
||||||
{
|
|
||||||
char *argvp = NULL;
|
|
||||||
ret = lwp_data_get(lwp, &argvp, &((char **)lwp->args)[1 + i], sizeof(argvp));
|
|
||||||
if (ret == 0)
|
|
||||||
{
|
|
||||||
lwp_free_command_line_args(argv);
|
|
||||||
return RT_NULL;
|
|
||||||
}
|
|
||||||
len = lwp_user_strlen_ext(lwp, argvp);
|
|
||||||
|
|
||||||
if (len > 0)
|
|
||||||
{
|
|
||||||
argv[i] = (char*)rt_malloc(len + 1);
|
|
||||||
ret = lwp_data_get(lwp, argv[i], argvp, len);
|
|
||||||
if (ret == 0)
|
|
||||||
{
|
|
||||||
lwp_free_command_line_args(argv);
|
|
||||||
return RT_NULL;
|
|
||||||
}
|
|
||||||
argv[i][len] = '\0';
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
argv[i] = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
argv[argc] = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return argv;
|
|
||||||
}
|
|
||||||
|
|
||||||
void lwp_free_command_line_args(char** argv)
|
|
||||||
{
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
if (argv)
|
|
||||||
{
|
|
||||||
for (i = 0; argv[i]; i++)
|
|
||||||
{
|
|
||||||
rt_free(argv[i]);
|
|
||||||
}
|
|
||||||
rt_free(argv);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -151,9 +151,6 @@ void lwp_unmap_user_space(struct rt_lwp *lwp);
|
||||||
int lwp_unmap_user(struct rt_lwp *lwp, void *va);
|
int lwp_unmap_user(struct rt_lwp *lwp, void *va);
|
||||||
void *lwp_map_user(struct rt_lwp *lwp, void *map_va, size_t map_size, rt_bool_t text);
|
void *lwp_map_user(struct rt_lwp *lwp, void *map_va, size_t map_size, rt_bool_t text);
|
||||||
|
|
||||||
void lwp_free_command_line_args(char** argv);
|
|
||||||
char** lwp_get_command_line_args(struct rt_lwp *lwp);
|
|
||||||
|
|
||||||
rt_varea_t lwp_map_user_varea(struct rt_lwp *lwp, void *map_va, size_t map_size);
|
rt_varea_t lwp_map_user_varea(struct rt_lwp *lwp, void *map_va, size_t map_size);
|
||||||
|
|
||||||
/* check LWP_MAP_FLAG_* */
|
/* check LWP_MAP_FLAG_* */
|
||||||
|
|
Loading…
Reference in New Issue