69575975f4
to avoid up_addrenv_destroy delete the current task page table this patch fix the below panic due to elf contain the unresolved symbol: qemu-system-arm -s -S -semihosting -M sabrelite -m 1024 -smp 4 -kernel nuttx -nographic -net nic -net user,hostfwd=tcp:127.0.0.1:10023-10.0.2.15:23,hostfwd=tcp:127.0.0.1:10021-10.0.2.15:21,hostfwd=tcp:127.0.0.1:15001-10.0.2.15:5001,hostfwd=tcp:127.0.0.1:15555-10.0.2.15:5555 ABDGHIJKNOPQ [ 0.470000] elf_relocate: Section 2 reloc 163: Failed to get value of symbol[1505]: -2 [ 0.530000] arm_dataabort: Data abort. PC: 108323de DFAR: 80202778 DFSR: 00000005 [ 0.530000] up_assert: Assertion failed at file:armv7-a/arm_dataabort.c line: 161 task: /system/bin/init [ 0.530000] arm_registerdump: R0: 10845820 R1: 80202778 R2: 00000001 R3: 80202778 [ 0.530000] arm_registerdump: R4: 80202624 R5: 80202634 R6: 80200330 FP: 80202628 [ 0.530000] arm_registerdump: R8: 802026b4 SB: 00000000 SL: 8000dbfe R11: 00000000 [ 0.530000] arm_registerdump: IP: 108453e0 SP: 108456b0 LR: 1082b091 PC: 108323de [ 0.530000] arm_registerdump: CPSR: a000007f [ 0.530000] arm_dump_stack: IRQ Stack: [ 0.530000] arm_dump_stack: sp: 10845510 [ 0.530000] arm_dump_stack: base: 108397c0 [ 0.530000] arm_dump_stack: size: 00000800 [ 0.530000] arm_dump_stack: ERROR: IRQ Stack pointer is not within the stack [ 0.530000] arm_stackdump: 10839f00: deadbeef 00adbeef 00000001 10844990 00000000 00000000 80300000 1082f2ef [ 0.530000] arm_stackdump: 10839f20: deadbeef 00000000 deadbeef 10844990 80200000 1082f2ff 1083d980 1082f311 [ 0.530000] arm_stackdump: 10839f40: 00000002 10814659 00000004 00000002 deadbeef 1081469b 00000001 00000000 [ 0.530000] arm_stackdump: 10839f60: 10845460 00000057 10844a90 00000002 deadbeef 10808d1b 10845460 00000057 [ 0.530000] arm_stackdump: 10839f80: 00dfbeef 00000057 00000000 00000002 deadbeef 10801d1f 10845460 00000057 [ 0.530000] arm_stackdump: 10839fa0: 00000000 10800fc5 deadbeef 10845460 00000057 00000057 deadbeef 108000a0 [ 0.530000] arm_dump_stack: User Stack: [ 0.530000] arm_dump_stack: sp: 108456b0 [ 0.530000] arm_dump_stack: base: 80202038 [ 0.530000] arm_dump_stack: size: 000007c8 [ 0.530000] arm_dump_stack: ERROR: User Stack pointer is not within the stack [ 0.530000] arm_dump_stack: Kernel Stack: [ 0.530000] arm_dump_stack: sp: 108456b0 [ 0.530000] arm_dump_stack: base: 10844c10 [ 0.530000] arm_dump_stack: size: 00000c00 [ 0.530000] arm_stackdump: 108456a0: 00000000 108453e0 108323de a000007f 80202778 10845820 00000000 10812aa9 [ 0.530000] arm_stackdump: 108456c0: 00000000 1083ff90 10845838 00000000 001f001e 10812b2f 10840008 1083ff90 [ 0.530000] arm_stackdump: 108456e0: 10845840 10812fab 10845840 1083ff90 005f0000 10844990 10845818 10845ff8 [ 0.530000] arm_stackdump: 10845700: 10845ff8 10845838 10845840 10812017 fffffffe 10845820 80202624 1082b091 [ 0.530000] arm_stackdump: 10845720: 00000000 00000000 80202778 10841d40 00000000 10845840 10845820 fffffffe [ 0.530000] arm_stackdump: 10845740: 00000000 1082998b 00000000 80200330 802026b4 80202778 10845788 0084578c [ 0.530000] arm_stackdump: 10845760: 10841d40 10844990 00000000 108306fb 00000000 80202634 802026b4 80202634 [ 0.530000] arm_stackdump: 10845780: 80202778 80202628 00000000 00000000 00000000 00000000 00000000 1083085f [ 0.530000] arm_stackdump: 108457a0: 80200330 00000000 00000000 00000000 80202634 80202624 80202778 80202628 [ 0.530000] arm_stackdump: 108457c0: 00000000 00000000 00000000 80202614 80202624 1080f26b 802026b4 80200330 [ 0.530000] arm_stackdump: 108457e0: 80202624 80202778 80202628 0000001f 00000000 80202634 802026b4 108012c3 [ 0.530000] arm_showtasks: PID PRI STACK USED FILLED COMMAND [ 0.530000] arm_showtasks: ---- ---- 2048 188 9.1% irq [ 0.530000] arm_dump_task: 0 0 2024 1240 61.2% Idle Task [ 0.530000] arm_dump_task: 1 224 1992 504 25.3% hpwork 0x1083e0f8 [ 0.530000] arm_dump_task: 2 100 1992 504 25.3% lpwork 0x1083e110 after apply this patch, nsh report error instead of crash: qemu-system-arm -s -S -semihosting -M sabrelite -m 1024 -smp 4 -kernel nuttx -nographic -net nic -net user,hostfwd=tcp:127.0.0.1:10023-10.0.2.15:23,hostfwd=tcp:127.0.0.1:10021-10.0.2.15:21,hostfwd=tcp:127.0.0.1:15001-10.0.2.15:5001,hostfwd=tcp:127.0.0.1:15555-10.0.2.15:5555 ABDGHIJKNOPQ [ 0.440000] elf_relocate: Section 2 reloc 163: Failed to get value of symbol[1505]: -2 telnetd [4:100] NuttShell (NSH) NuttX-11.0.0 nsh> nsh: telnetd: command not found Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
294 lines
8.5 KiB
C
294 lines
8.5 KiB
C
/****************************************************************************
|
|
* binfmt/libelf/libelf_addrenv.c
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed with
|
|
* this work for additional information regarding copyright ownership. The
|
|
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
|
* "License"); you may not use this file except in compliance with the
|
|
* License. You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
* License for the specific language governing permissions and limitations
|
|
* under the License.
|
|
*
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Included Files
|
|
****************************************************************************/
|
|
|
|
#include <nuttx/config.h>
|
|
|
|
#include <errno.h>
|
|
#include <debug.h>
|
|
|
|
#include <nuttx/arch.h>
|
|
#include <nuttx/kmalloc.h>
|
|
|
|
#include <sys/mman.h>
|
|
|
|
#include "libelf.h"
|
|
|
|
/****************************************************************************
|
|
* Pre-processor Definitions
|
|
****************************************************************************/
|
|
|
|
#define ELF_TEXT_WRE (PROT_READ | PROT_WRITE | PROT_EXEC)
|
|
#define ELF_TEXT_WRD (PROT_READ | PROT_EXEC)
|
|
|
|
/****************************************************************************
|
|
* Private Constant Data
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Private Functions
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Public Functions
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Name: elf_addrenv_alloc
|
|
*
|
|
* Description:
|
|
* Allocate memory for the ELF image (textalloc and dataalloc). If
|
|
* CONFIG_ARCH_ADDRENV=n, textalloc will be allocated using kmm_zalloc()
|
|
* and dataalloc will be a offset from textalloc. If
|
|
* CONFIG_ARCH_ADDRENV=y, then textalloc and dataalloc will be allocated
|
|
* using up_addrenv_create(). In either case, there will be a unique
|
|
* instance of textalloc and dataalloc (and stack) for each instance of a
|
|
* process.
|
|
*
|
|
* Input Parameters:
|
|
* loadinfo - Load state information
|
|
* textsize - The size (in bytes) of the .text address environment needed
|
|
* for the ELF image (read/execute).
|
|
* datasize - The size (in bytes) of the .bss/.data address environment
|
|
* needed for the ELF image (read/write).
|
|
* heapsize - The initial size (in bytes) of the heap address environment
|
|
* needed by the task. This region may be read/write only.
|
|
*
|
|
* Returned Value:
|
|
* Zero (OK) on success; a negated errno value on failure.
|
|
*
|
|
****************************************************************************/
|
|
|
|
int elf_addrenv_alloc(FAR struct elf_loadinfo_s *loadinfo, size_t textsize,
|
|
size_t datasize, size_t heapsize)
|
|
{
|
|
#ifdef CONFIG_ARCH_ADDRENV
|
|
FAR void *vtext;
|
|
FAR void *vdata;
|
|
int ret;
|
|
|
|
/* Create an address environment for the new ELF task */
|
|
|
|
ret = up_addrenv_create(textsize, datasize, heapsize, &loadinfo->addrenv);
|
|
if (ret < 0)
|
|
{
|
|
berr("ERROR: up_addrenv_create failed: %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
/* Get the virtual address associated with the start of the address
|
|
* environment. This is the base address that we will need to use to
|
|
* access the ELF image (but only if the address environment has been
|
|
* selected.
|
|
*/
|
|
|
|
ret = up_addrenv_vtext(&loadinfo->addrenv, &vtext);
|
|
if (ret < 0)
|
|
{
|
|
berr("ERROR: up_addrenv_vtext failed: %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
ret = up_addrenv_vdata(&loadinfo->addrenv, textsize, &vdata);
|
|
if (ret < 0)
|
|
{
|
|
berr("ERROR: up_addrenv_vdata failed: %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
loadinfo->textalloc = (uintptr_t)vtext;
|
|
loadinfo->dataalloc = (uintptr_t)vdata;
|
|
return OK;
|
|
#else
|
|
/* Allocate memory to hold the ELF image */
|
|
|
|
#if defined(CONFIG_ARCH_USE_TEXT_HEAP)
|
|
loadinfo->textalloc = (uintptr_t)
|
|
up_textheap_memalign(loadinfo->textalign,
|
|
textsize);
|
|
#else
|
|
loadinfo->textalloc = (uintptr_t)kumm_memalign(loadinfo->textalign,
|
|
textsize);
|
|
#endif
|
|
|
|
if (!loadinfo->textalloc)
|
|
{
|
|
return -ENOMEM;
|
|
}
|
|
|
|
if (loadinfo->datasize > 0)
|
|
{
|
|
loadinfo->dataalloc = (uintptr_t)kumm_memalign(loadinfo->dataalign,
|
|
datasize);
|
|
if (!loadinfo->dataalloc)
|
|
{
|
|
return -ENOMEM;
|
|
}
|
|
}
|
|
|
|
return OK;
|
|
#endif
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: elf_addrenv_select
|
|
*
|
|
* Description:
|
|
* Temporarily select the task's address environment.
|
|
*
|
|
* Input Parameters:
|
|
* loadinfo - Load state information
|
|
*
|
|
* Returned Value:
|
|
* Zero (OK) on success; a negated errno value on failure.
|
|
*
|
|
****************************************************************************/
|
|
|
|
#ifdef CONFIG_ARCH_ADDRENV
|
|
int elf_addrenv_select(FAR struct elf_loadinfo_s *loadinfo)
|
|
{
|
|
int ret;
|
|
|
|
/* Instantiate the new address environment */
|
|
|
|
ret = up_addrenv_select(&loadinfo->addrenv, &loadinfo->oldenv);
|
|
if (ret < 0)
|
|
{
|
|
berr("ERROR: up_addrenv_select failed: %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
/* Allow write access to .text */
|
|
|
|
ret = up_addrenv_mprot(&loadinfo->addrenv, loadinfo->textalloc,
|
|
loadinfo->textsize, ELF_TEXT_WRE);
|
|
if (ret < 0)
|
|
{
|
|
berr("ERROR: up_addrenv_text_enable_write failed: %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
* Name: elf_addrenv_restore
|
|
*
|
|
* Description:
|
|
* Restore the address environment before elf_addrenv_select() was called..
|
|
*
|
|
* Input Parameters:
|
|
* loadinfo - Load state information
|
|
*
|
|
* Returned Value:
|
|
* Zero (OK) on success; a negated errno value on failure.
|
|
*
|
|
****************************************************************************/
|
|
|
|
#ifdef CONFIG_ARCH_ADDRENV
|
|
int elf_addrenv_restore(FAR struct elf_loadinfo_s *loadinfo)
|
|
{
|
|
int ret;
|
|
|
|
/* Remove write access to .text */
|
|
|
|
ret = up_addrenv_mprot(&loadinfo->addrenv, loadinfo->textalloc,
|
|
loadinfo->textsize, ELF_TEXT_WRD);
|
|
if (ret < 0)
|
|
{
|
|
berr("ERROR: up_addrenv_text_disable_write failed: %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
/* Restore the old address environment */
|
|
|
|
ret = up_addrenv_restore(&loadinfo->oldenv);
|
|
if (ret < 0)
|
|
{
|
|
berr("ERROR: up_addrenv_restore failed: %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
* Name: elf_addrenv_free
|
|
*
|
|
* Description:
|
|
* Release the address environment previously created by
|
|
* elf_addrenv_alloc(). This function is called only under certain error
|
|
* conditions after the module has been loaded but not yet started.
|
|
* After the module has been started, the address environment will
|
|
* automatically be freed when the module exits.
|
|
*
|
|
* Input Parameters:
|
|
* loadinfo - Load state information
|
|
*
|
|
* Returned Value:
|
|
* None.
|
|
*
|
|
****************************************************************************/
|
|
|
|
void elf_addrenv_free(FAR struct elf_loadinfo_s *loadinfo)
|
|
{
|
|
#ifdef CONFIG_ARCH_ADDRENV
|
|
int ret;
|
|
|
|
/* Free the address environment */
|
|
|
|
elf_addrenv_select(loadinfo);
|
|
ret = up_addrenv_destroy(&loadinfo->addrenv);
|
|
elf_addrenv_restore(loadinfo);
|
|
if (ret < 0)
|
|
{
|
|
berr("ERROR: up_addrenv_destroy failed: %d\n", ret);
|
|
}
|
|
#else
|
|
|
|
if (loadinfo->textalloc != 0)
|
|
{
|
|
#if defined(CONFIG_ARCH_USE_TEXT_HEAP)
|
|
up_textheap_free((FAR void *)loadinfo->textalloc);
|
|
#else
|
|
kumm_free((FAR void *)loadinfo->textalloc);
|
|
#endif
|
|
}
|
|
|
|
if (loadinfo->dataalloc != 0)
|
|
{
|
|
kumm_free((FAR void *)loadinfo->dataalloc);
|
|
}
|
|
|
|
#endif
|
|
|
|
/* Clear out all indications of the allocated address environment */
|
|
|
|
loadinfo->textalloc = 0;
|
|
loadinfo->dataalloc = 0;
|
|
loadinfo->textsize = 0;
|
|
loadinfo->datasize = 0;
|
|
}
|