summaryrefslogtreecommitdiffstatsabout
diff options
context:
space:
mode:
authorGavin.Bai <gavin_8724@163.com>2019-11-13 09:13:32 (GMT)
committer Gavin.Bai <gavin_8724@163.com>2019-11-13 09:13:32 (GMT)
commit041107f73bd620a7b720c3f01a000be885a4d39b (patch)
treee4b0c135cfd9092d44836a4beb03c59e76cd48b1
parent80e35685b59d74edf66e3a6fe4072f84b843fdd3 (diff)
downloadAIC-OS-041107f73bd620a7b720c3f01a000be885a4d39b.zip
Update base repo from open source git.
-rw-r--r--Makefile2
-rw-r--r--SylixOS/arch/arm/common/armContext.c2
-rw-r--r--SylixOS/arch/csky/backtrace/cskyBacktrace.c22
-rw-r--r--SylixOS/arch/csky/common/cskyExc.c30
-rw-r--r--SylixOS/arch/csky/common/cskyExcAsm.S1
-rw-r--r--SylixOS/arch/csky/common/unaligned/cskyUnaligned.c43
-rw-r--r--SylixOS/arch/csky/common/unaligned/cskyUnaligned.h2
-rw-r--r--SylixOS/arch/csky/fpu/fpu/cskyVfp.c57
-rw-r--r--SylixOS/arch/csky/fpu/fpu/cskyVfp.h3
-rw-r--r--SylixOS/arch/csky/fpu/fpu/cskyVfpAsm.S124
-rw-r--r--SylixOS/arch/csky/mm/mmu/cskyMmu.c1
-rw-r--r--SylixOS/arch/mips/backtrace/mipsBacktrace.c21
-rw-r--r--SylixOS/arch/mips/common/mipsExc.c25
-rw-r--r--SylixOS/arch/mips/common/unaligned/mipsUnaligned.c31
-rw-r--r--SylixOS/arch/mips/common/unaligned/mipsUnaligned.h2
-rw-r--r--SylixOS/arch/mips/dsp/hr2vector/mipsHr2Vector.c26
-rw-r--r--SylixOS/arch/mips/dsp/hr2vector/mipsHr2VectorAsm.S195
-rw-r--r--SylixOS/arch/mips/elf/mipsElf32.c2
-rw-r--r--SylixOS/arch/mips/mm/cache/hr2/mipsCacheHr2.c60
-rw-r--r--SylixOS/arch/mips/mm/cache/hr2/mipsCacheHr2Asm.S15
-rw-r--r--SylixOS/arch/mips/mm/mmu/mipsMmuCommon.c4
-rw-r--r--SylixOS/arch/ppc/common/e500/ppcExcE500.c16
-rw-r--r--SylixOS/arch/ppc/common/ppcContext.c3
-rw-r--r--SylixOS/arch/ppc/common/ppcExc.c16
-rw-r--r--SylixOS/arch/ppc/common/unaligned/porting.h6
-rw-r--r--SylixOS/arch/ppc/common/unaligned/ppcUnaligned.c33
-rw-r--r--SylixOS/arch/ppc/common/unaligned/ppcUnaligned.h2
-rw-r--r--SylixOS/arch/riscv/common/riscvExc.c60
-rw-r--r--SylixOS/arch/riscv/common/unaligned/bits.h61
-rw-r--r--SylixOS/arch/riscv/common/unaligned/config.h32
-rw-r--r--SylixOS/arch/riscv/common/unaligned/emulation.h80
-rw-r--r--SylixOS/arch/riscv/common/unaligned/fp_asm.S235
-rw-r--r--SylixOS/arch/riscv/common/unaligned/fp_emulation.h76
-rw-r--r--SylixOS/arch/riscv/common/unaligned/misaligned_ldst.c184
-rw-r--r--SylixOS/arch/riscv/common/unaligned/riscvUnaligned.c71
-rw-r--r--SylixOS/arch/riscv/common/unaligned/riscvUnaligned.h35
-rw-r--r--SylixOS/arch/riscv/common/unaligned/unprivileged_memory.h129
-rw-r--r--SylixOS/arch/sparc/backtrace/sparcBacktrace.c8
-rw-r--r--SylixOS/arch/sparc/common/sparcExc.c31
-rw-r--r--SylixOS/arch/sparc/common/unaligned/sparcUnaligned.c (renamed from SylixOS/arch/sparc/common/sparcUnaligned.c)56
-rw-r--r--SylixOS/arch/sparc/common/unaligned/sparcUnaligned.h30
-rw-r--r--SylixOS/arch/sparc/common/unaligned/sparcUnalignedAsm.S (renamed from SylixOS/arch/sparc/common/sparcUnalignedAsm.S)0
-rw-r--r--SylixOS/bintools/demangle/ansidecl.h313
-rw-r--r--SylixOS/bintools/demangle/cp-demangle.c6371
-rw-r--r--SylixOS/bintools/demangle/cp-demangle.h174
-rw-r--r--SylixOS/bintools/demangle/cp-demint.c264
-rw-r--r--SylixOS/bintools/demangle/demangle.c35
-rw-r--r--SylixOS/bintools/demangle/demangle.h679
-rw-r--r--SylixOS/bintools/demangle/libiberty.h686
-rw-r--r--SylixOS/config/cpu/cpu_cfg_csky.h6
-rw-r--r--SylixOS/config/cpu/cpu_cfg_ppc.h4
-rw-r--r--SylixOS/config/driver/drv_cfg.h6
-rw-r--r--SylixOS/config/mp/mp_cfg.h4
-rw-r--r--SylixOS/config/net/net_cfg.h6
-rw-r--r--SylixOS/config/net/net_perf_cfg.h3
-rw-r--r--SylixOS/config/system/system_cfg.h2
-rw-r--r--SylixOS/driver/can/sja1000.c9
-rw-r--r--SylixOS/hosttools/makelitesymbol/makelitesymbol.bat1
-rw-r--r--SylixOS/hosttools/makesymbol/makesymbol.bat4
-rw-r--r--SylixOS/hosttools/makesymbol/makesymbol.sh1
-rw-r--r--SylixOS/include/arch/csky/inc/cskyregs.h14
-rw-r--r--SylixOS/include/linux/compat.h22
-rw-r--r--SylixOS/kernel/cache/cache.c15
-rw-r--r--SylixOS/kernel/cdump/cdumpLib.c46
-rw-r--r--SylixOS/kernel/include/k_kernel.h2
-rw-r--r--SylixOS/kernel/include/k_logo.h28
-rw-r--r--SylixOS/kernel/show/BacktraceShow.c47
-rw-r--r--SylixOS/kernel/vmm/vmm.h26
-rw-r--r--SylixOS/kernel/vmm/vmmAbort.c250
-rw-r--r--SylixOS/kernel/vmm/vmmSwap.h20
-rw-r--r--SylixOS/kidvpn/kv_lib.c11
-rw-r--r--SylixOS/loader/elf/elf_loader.c45
-rw-r--r--SylixOS/loader/src/loader_vppatch.c78
-rw-r--r--SylixOS/mktemp/application.mk23
-rw-r--r--SylixOS/mktemp/bsp.mk4
-rw-r--r--SylixOS/mktemp/cl6x.mk1
-rw-r--r--SylixOS/mktemp/clear-vars.mk5
-rw-r--r--SylixOS/mktemp/common.mk2
-rw-r--r--SylixOS/mktemp/gcc.mk1
-rw-r--r--SylixOS/mktemp/gtest.mk13
-rw-r--r--SylixOS/mktemp/header.mk2
-rw-r--r--SylixOS/mktemp/mkdemo/application/application.mk5
-rw-r--r--SylixOS/mktemp/mkdemo/gtest/gtest.mk5
-rw-r--r--SylixOS/mktemp/mkdemo/unit-test/unit-test.mk5
-rw-r--r--SylixOS/mktemp/unit-test.mk18
-rw-r--r--SylixOS/net/lwip/flowctl/cor_flowctl.c440
-rw-r--r--SylixOS/net/lwip/flowctl/cor_flowctl.h113
-rw-r--r--SylixOS/net/lwip/flowctl/ip4_flowctl.c498
-rw-r--r--SylixOS/net/lwip/flowctl/ip4_flowctl.h93
-rw-r--r--SylixOS/net/lwip/flowctl/ip6_flowctl.c571
-rw-r--r--SylixOS/net/lwip/flowctl/ip6_flowctl.h108
-rw-r--r--SylixOS/net/lwip/flowctl/net_flowctl.c441
-rw-r--r--SylixOS/net/lwip/flowctl/net_flowctl.h86
-rw-r--r--SylixOS/net/lwip/lwip_fix.c29
-rw-r--r--SylixOS/net/lwip/lwip_fix.h25
-rw-r--r--SylixOS/net/lwip/lwip_flowctl.c763
-rw-r--r--SylixOS/net/lwip/lwip_flowsh.c811
-rw-r--r--SylixOS/net/lwip/lwip_ifctl.c2
-rw-r--r--SylixOS/net/lwip/mem/tlsf.c12
-rw-r--r--SylixOS/net/lwip/mem/tlsf_mem.c12
-rw-r--r--SylixOS/net/lwip/src/netif/lowpan6_common.c31
-rw-r--r--SylixOS/net/lwip/src/netif/radio/aes_crypt.c244
-rw-r--r--SylixOS/net/lwip/src/netif/radio/aes_crypt.h49
-rw-r--r--SylixOS/net/lwip/src/netif/radio/ieee802154_aes.c541
-rw-r--r--SylixOS/net/lwip/src/netif/radio/ieee802154_aes.h50
-rw-r--r--SylixOS/net/lwip/src/netif/radio/ieee802154_aes_ccm.c627
-rw-r--r--SylixOS/net/lwip/src/netif/radio/ieee802154_aes_ccm.h60
-rw-r--r--SylixOS/net/lwip/src/netif/radio/simple_crypt.c111
-rw-r--r--SylixOS/net/lwip/src/netif/radio/simple_crypt.h48
-rw-r--r--SylixOS/net/lwip/tools/ftp/lwip_ftpd.c4
-rw-r--r--SylixOS/net/lwip/tools/telnet/lwip_telnet.c4
-rw-r--r--SylixOS/shell/ttinyShell/ttinyShell.c21
-rw-r--r--SylixOS/shell/ttinyShell/ttinyShellSysCmd.c12
-rw-r--r--SylixOS/symbol/symTable/symTable.c2
-rw-r--r--SylixOS/system/device/rand/randDevLib.c14
-rw-r--r--SylixOS/system/signal/signal.h8
-rw-r--r--demangle.mk76
-rw-r--r--environ.mk2
-rw-r--r--libsylixos.mk7
-rw-r--r--ls.mk74
120 files changed, 16486 insertions, 591 deletions
diff --git a/Makefile b/Makefile
index a7b4119..4f58ca0 100644
--- a/Makefile
+++ b/Makefile
@@ -97,6 +97,8 @@ include libdsohandle.mk
include libvpmpdm.mk
include environ.mk
include dd.mk
+include demangle.mk
+include ls.mk
ifneq ($(ARCH), c6x)
include libstdc++.mk
endif
diff --git a/SylixOS/arch/arm/common/armContext.c b/SylixOS/arch/arm/common/armContext.c
index ae98d8f..873e4be 100644
--- a/SylixOS/arch/arm/common/armContext.c
+++ b/SylixOS/arch/arm/common/armContext.c
@@ -103,7 +103,7 @@ VOID archTaskCtxSetFp (PLW_STACK pstkDest,
* add fp, sp, #4
*/
pfpctx->FP_uiFp = pregctxSrc->REG_uiFp;
- pfpctx->FP_uiLr = pregctxSrc->REG_uiLr;
+ pfpctx->FP_uiLr = pregctxSrc->REG_uiPc;
pregctxDest->REG_uiFp = (ARCH_REG_T)&pfpctx->FP_uiLr;
}
diff --git a/SylixOS/arch/csky/backtrace/cskyBacktrace.c b/SylixOS/arch/csky/backtrace/cskyBacktrace.c
index c0b7e4c..cd4c465 100644
--- a/SylixOS/arch/csky/backtrace/cskyBacktrace.c
+++ b/SylixOS/arch/csky/backtrace/cskyBacktrace.c
@@ -122,7 +122,7 @@ static void csky_analyze_prologue (unsigned long start_pc, unsigned long
insn_len = 2; /* instruction is 16bit */
for (addr = start_pc; addr < limit_pc; addr += insn_len) {
- insn_len = csky_get_insn (addr, &insn); /* Get next insn */
+ insn_len = csky_get_insn(addr, &insn); /* Get next insn */
if(insn_len == 4) { /* if 32bit */
if (V2_32_IS_SUBI0(insn)) { /* subi32 sp,sp oimm12 */
@@ -184,7 +184,7 @@ static void csky_analyze_prologue (unsigned long start_pc, unsigned long
addr += 4;
mfcr_regnum = insn & 0x1f;
- insn_len = csky_get_insn (addr, &insn2);
+ insn_len = csky_get_insn(addr, &insn2);
if (insn_len == 2) {
stw_regnum = (insn2 >> 5) & 0x7;
if (V2_16_IS_STWx0(insn2) && (mfcr_regnum == stw_regnum)) {
@@ -215,7 +215,7 @@ static void csky_analyze_prologue (unsigned long start_pc, unsigned long
addr += 4;
mfcr_regnum = insn & 0x1f;
- insn_len = csky_get_insn (addr, &insn2);
+ insn_len = csky_get_insn(addr, &insn2);
if (insn_len == 2) {
stw_regnum = (insn2 >> 5) & 0x7;
if (V2_16_IS_STWx0(insn2) && (mfcr_regnum == stw_regnum)) {
@@ -247,7 +247,7 @@ static void csky_analyze_prologue (unsigned long start_pc, unsigned long
addr += 4;
mfcr_regnum = insn & 0x1f;
- insn_len = csky_get_insn (addr, &insn2);
+ insn_len = csky_get_insn(addr, &insn2);
if (insn_len == 2) {
stw_regnum = (insn2 >> 5) & 0x7;
if (V2_16_IS_STWx0(insn2) && (mfcr_regnum == stw_regnum)) {
@@ -278,7 +278,7 @@ static void csky_analyze_prologue (unsigned long start_pc, unsigned long
addr += 4;
mfcr_regnum = insn & 0x1f;
- insn_len = csky_get_insn (addr, &insn2);
+ insn_len = csky_get_insn(addr, &insn2);
if (insn_len == 2) {
stw_regnum = (insn2 >> 5) & 0x7;
if (V2_16_IS_STWx0(insn2) && (mfcr_regnum == stw_regnum)) {
@@ -376,7 +376,7 @@ static void csky_analyze_prologue (unsigned long start_pc, unsigned long
} else if (V2_32_IS_MOVIH4(insn)) {
adjust = (insn & 0xffff) << 16;
- } else { /* V2_32_IS_BMASKI4 (insn) */
+ } else { /* V2_32_IS_BMASKI4(insn) */
adjust = (1 << (((insn & 0x3e00000) >> 21) + 1)) - 1;
}
@@ -456,7 +456,7 @@ static void csky_analyze_prologue (unsigned long start_pc, unsigned long
offset += insn_len;
insn_len = csky_get_insn(addr + offset, &insn2);
- };
+ }
/*
* If the next insn adjusts the stack pointer, we keep everything;
@@ -556,7 +556,7 @@ static void csky_analyze_prologue (unsigned long start_pc, unsigned long
* May have zero or more insns which modify r4
*/
offset = 2;
- insn_len = csky_get_insn (addr + offset, &insn2);
+ insn_len = csky_get_insn(addr + offset, &insn2);
while (V2_IS_R4_ADJUSTER(insn2)) {
if (V2_32_IS_ADDI4(insn2)) {
@@ -630,7 +630,7 @@ static void csky_analyze_prologue (unsigned long start_pc, unsigned long
}
offset += insn_len;
- insn_len = csky_get_insn (addr + offset, &insn2);
+ insn_len = csky_get_insn(addr + offset, &insn2);
}
/*
@@ -719,7 +719,7 @@ __find_start:
(V2_32_IS_POP((*(addr - 1) << 16 | inst)) && V2_16_IS_MOV_SP_FP(*(addr - 2)))) {
temp_pc = (unsigned long)(addr - 2);
addr++;
- addr = (CSKY_INSTRUCTION *)ROUND_UP(addr, 4);
+ addr = (CSKY_INSTRUCTION *)ROUND_UP(addr, 4);
for ( ; ; addr++) {
inst = *addr;
@@ -747,7 +747,7 @@ __find_start:
goto __find_start;
}
- for (addr = (CSKY_INSTRUCTION *)start_pc; ; addr++) { /* 查找函数结束结束地址 */
+ for (addr = (CSKY_INSTRUCTION *)start_pc; ; addr++) { /* 查找函数结束结束地址 */
inst = *addr;
if (IS_T32(inst)) {
diff --git a/SylixOS/arch/csky/common/cskyExc.c b/SylixOS/arch/csky/common/cskyExc.c
index 9471bc2..77950d9 100644
--- a/SylixOS/arch/csky/common/cskyExc.c
+++ b/SylixOS/arch/csky/common/cskyExc.c
@@ -22,11 +22,15 @@
#define __SYLIXOS_KERNEL
#include "SylixOS.h"
#include "dtrace.h"
+#include "arch/csky/inc/cskyregs.h"
+#include "arch/csky/param/cskyParam.h"
#include "arch/csky/common/unaligned/cskyUnaligned.h"
#if LW_CFG_VMM_EN > 0
#include "arch/csky/mm/mmu/cskyMmu.h"
#endif
-#include "arch/csky/param/cskyParam.h"
+#if LW_CFG_CPU_FPU_EN > 0
+#include "arch/csky/fpu/fpu/cskyVfp.h"
+#endif
/*********************************************************************************************************
C-SKY 体系架构
*********************************************************************************************************/
@@ -316,6 +320,9 @@ VOID archReservedExceptHandle (ULONG ulVector, ARCH_REG_CTX *pregctx)
{
LW_VMM_ABORT abtInfo;
PLW_CLASS_TCB ptcbCur;
+#if LW_CFG_CPU_FPU_EN > 0
+ UINT32 uiFESR;
+#endif /* LW_CFG_CPU_FPU_EN > 0 */
LW_TCB_GET_CUR(ptcbCur);
@@ -509,6 +516,21 @@ VOID archAccessExceptHandle (ULONG ulVector, ARCH_REG_CTX *pregctx)
API_VmmAbortIsr(pregctx->REG_ulPc, pregctx->REG_ulMeh, &abtInfo, ptcbCur);
}
/*********************************************************************************************************
+** 函数名称: archUnalignedHandle
+** 功能描述: 非对齐内存访问异常处理
+** 输 入 : pabtctx abort 上下文
+** 输 出 : NONE
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static VOID archUnalignedHandle (PLW_VMM_ABORT_CTX pabtctx)
+{
+ cskyUnalignedHandle(&pabtctx->ABTCTX_archRegCtx,
+ &pabtctx->ABTCTX_abtInfo);
+
+ API_VmmAbortReturn(pabtctx);
+}
+/*********************************************************************************************************
** 函数名称: archUnalignedExceptHandle
** 功能描述: 未对齐访问异常处理
** 输 入 : ulVector 中断向量
@@ -521,13 +543,13 @@ VOID archUnalignedExceptHandle (ULONG ulVector, ARCH_REG_CTX *pregctx)
{
PLW_CLASS_TCB ptcbCur;
LW_VMM_ABORT abtInfo;
- CSKY_PARAM *param;
+ CSKY_PARAM *param = archKernelParamGet();
LW_TCB_GET_CUR(ptcbCur);
- abtInfo.VMABT_uiMethod = LW_VMM_ABORT_METHOD_READ;
+ abtInfo.VMABT_uiType = LW_VMM_ABORT_TYPE_BUS;
+ abtInfo.VMABT_uiMethod = BUS_ADRALN;
- param = archKernelParamGet();
if (param->CP_bUnalign) {
API_VmmAbortIsrEx(pregctx->REG_ulPc, pregctx->REG_ulPc, &abtInfo, ptcbCur, archUnalignedHandle);
diff --git a/SylixOS/arch/csky/common/cskyExcAsm.S b/SylixOS/arch/csky/common/cskyExcAsm.S
index beb1bb7..52714aa 100644
--- a/SylixOS/arch/csky/common/cskyExcAsm.S
+++ b/SylixOS/arch/csky/common/cskyExcAsm.S
@@ -186,7 +186,6 @@ MACRO_DEF(IRQ_ENTRY irq handle)
SUBI SP , ARCH_REG_CTX_SIZE
MOV A1 , SP
BR 2b
- RESTORE_REGS
MACRO_END()
;/*********************************************************************************************************
diff --git a/SylixOS/arch/csky/common/unaligned/cskyUnaligned.c b/SylixOS/arch/csky/common/unaligned/cskyUnaligned.c
index 71e1640..8eff690 100644
--- a/SylixOS/arch/csky/common/unaligned/cskyUnaligned.c
+++ b/SylixOS/arch/csky/common/unaligned/cskyUnaligned.c
@@ -806,22 +806,22 @@ fault:
/*********************************************************************************************************
** 函数名称: cskyUnalignedHandle
** 功能描述: C-SKY 非对齐处理
-** 输 入 : regs 寄存器上下文
-** ulAbortAddr 终止地址
-** 输 出 : 终止类型
+** 输 入 : pregctx 寄存器上下文
+** pabtInfo 终止信息
+** 输 出 : NONE
** 全局变量:
** 调用模块:
*********************************************************************************************************/
-ULONG cskyUnalignedHandle (ARCH_REG_CTX *regs, addr_t ulAbortAddr)
+VOID cskyUnalignedHandle (ARCH_REG_CTX *pregctx, PLW_VMM_ABORT pabtInfo)
{
int err;
unsigned long instr = 0, instrptr;
unsigned int fault;
u16 tinstr = 0;
- int (*handler)(unsigned long inst, ARCH_REG_CTX *regs) = LW_NULL;
+ int (*handler)(unsigned long inst, ARCH_REG_CTX *pregctx) = LW_NULL;
int isize = 2;
- instrptr = instruction_pointer(regs);
+ instrptr = instruction_pointer(pregctx);
fault = __get_user(tinstr, (u16 *)(instrptr & ~1));
instr = (unsigned long)tinstr;
@@ -837,7 +837,7 @@ ULONG cskyUnalignedHandle (ARCH_REG_CTX *regs, addr_t ulAbortAddr)
#endif
if (fault) {
- goto bad_or_fault;
+ goto fault;
}
pregctx->REG_ulPc += isize;
@@ -862,11 +862,11 @@ ULONG cskyUnalignedHandle (ARCH_REG_CTX *regs, addr_t ulAbortAddr)
handler = handle_ldq_v1;
} else {
- goto bad_or_fault;
+ goto sigill;
}
#else /* abiv2 */
if (2 == isize) {
- switch(instr & 0xf800) {
+ switch (instr & 0xf800) {
case 0x8800: /* ldh */
handler = handle_ldh_16;
@@ -898,7 +898,7 @@ ULONG cskyUnalignedHandle (ARCH_REG_CTX *regs, addr_t ulAbortAddr)
break;
default:
- goto bad_or_fault;
+ goto sigill;
}
} else {
@@ -929,25 +929,36 @@ ULONG cskyUnalignedHandle (ARCH_REG_CTX *regs, addr_t ulAbortAddr)
/*
* FIXME: stq/stq is pseudo instruction of stm/stm and now ignore.
*/
- goto bad_or_fault;
+ goto sigill;
}
}
#endif
if (!handler) {
- goto bad_or_fault;
+ goto sigill;
}
- err = handler(instr, regs);
+ err = handler(instr, pregctx);
if (err != HANDLER_SUCCESS) {
pregctx->REG_ulPc -=2;
goto sigbus;
}
- return (0);
+ pabtInfo->VMABT_uiType = LW_VMM_ABORT_TYPE_NOINFO;
+ return;
+
+fault:
+ pabtInfo->VMABT_uiType = LW_VMM_ABORT_TYPE_TERMINAL;
+ return;
+
+sigbus:
+ pabtInfo->VMABT_uiType = LW_VMM_ABORT_TYPE_BUS;
+ pabtInfo->VMABT_uiMethod = BUS_ADRALN;
+ return;
-bad_or_fault:
- return (LW_VMM_ABORT_TYPE_BUS);
+sigill:
+ pabtInfo->VMABT_uiType = LW_VMM_ABORT_TYPE_UNDEF;
+ pabtInfo->VMABT_uiMethod = LW_VMM_ABORT_METHOD_EXEC;
}
/*********************************************************************************************************
END
diff --git a/SylixOS/arch/csky/common/unaligned/cskyUnaligned.h b/SylixOS/arch/csky/common/unaligned/cskyUnaligned.h
index 6e0438a..61c82b7 100644
--- a/SylixOS/arch/csky/common/unaligned/cskyUnaligned.h
+++ b/SylixOS/arch/csky/common/unaligned/cskyUnaligned.h
@@ -22,7 +22,7 @@
#ifndef __ARCH_CSKYUNALIGNED_H
#define __ARCH_CSKYUNALIGNED_H
-ULONG cskyUnalignedHandle(ARCH_REG_CTX *pregctx, addr_t ulAbortAddr);
+VOID cskyUnalignedHandle(ARCH_REG_CTX *pregctx, PLW_VMM_ABORT pabtInfo);
#endif /* __ARCH_CSKYUNALIGNED_H */
/*********************************************************************************************************
diff --git a/SylixOS/arch/csky/fpu/fpu/cskyVfp.c b/SylixOS/arch/csky/fpu/fpu/cskyVfp.c
index 235b47c..4d5ff63 100644
--- a/SylixOS/arch/csky/fpu/fpu/cskyVfp.c
+++ b/SylixOS/arch/csky/fpu/fpu/cskyVfp.c
@@ -29,16 +29,47 @@
/*********************************************************************************************************
全局变量
*********************************************************************************************************/
-static CSKY_FPU_OP _G_fpuopVfp;
+static CSKY_FPU_OP _G_fpuopVfp;
/*********************************************************************************************************
实现函数
*********************************************************************************************************/
-extern VOID cskyVfpInit(VOID);
-extern VOID cskyVfpEnable(VOID);
-extern VOID cskyVfpDisable(VOID);
-extern BOOL cskyVfpIsEnable(VOID);
-extern VOID cskyVfpSave(PVOID pvFpuCtx);
-extern VOID cskyVfpRestore(PVOID pvFpuCtx);
+extern VOID cskyVfpInit(VOID);
+extern VOID cskyVfpSave(PVOID pvFpuCtx);
+extern VOID cskyVfpRestore(PVOID pvFpuCtx);
+/*********************************************************************************************************
+** 函数名称: cskyVfpEnable
+** 功能描述: 使能 VFP
+** 输 入 : NONE
+** 输 出 : NONE
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static VOID cskyVfpEnable (VOID)
+{
+}
+/*********************************************************************************************************
+** 函数名称: cskyVfpDisable
+** 功能描述: 禁能 VFP
+** 输 入 : NONE
+** 输 出 : NONE
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static VOID cskyVfpDisable (VOID)
+{
+}
+/*********************************************************************************************************
+** 函数名称: cskyVfpIsEnable
+** 功能描述: 判断 VFP 是否使能
+** 输 入 : NONE
+** 输 出 : NONE
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static BOOL cskyVfpIsEnable (VOID)
+{
+ return (LW_TRUE);
+}
/*********************************************************************************************************
** 函数名称: cskyVfpCtxShow
** 功能描述: 显示 VFP 上下文
@@ -86,12 +117,12 @@ PCSKY_FPU_OP cskyVfpPrimaryInit (CPCHAR pcMachineName, CPCHAR pcFpuName)
cskyVfpInit();
- _G_fpuopVfp.CFPU_pfuncEnable = cskyVfpEnable;
- _G_fpuopVfp.CFPU_pfuncDisable = cskyVfpDisable;
- _G_fpuopVfp.CFPU_pfuncIsEnable = cskyVfpIsEnable;
- _G_fpuopVfp.CFPU_pfuncCtxShow = cskyVfpCtxShow;
- _G_fpuopVfp.CFPU_pfuncSave = cskyVfpSave;
- _G_fpuopVfp.CFPU_pfuncRestore = cskyVfpRestore;
+ _G_fpuopVfp.CFPU_pfuncEnable = cskyVfpEnable;
+ _G_fpuopVfp.CFPU_pfuncDisable = cskyVfpDisable;
+ _G_fpuopVfp.CFPU_pfuncIsEnable = cskyVfpIsEnable;
+ _G_fpuopVfp.CFPU_pfuncCtxShow = cskyVfpCtxShow;
+ _G_fpuopVfp.CFPU_pfuncSave = cskyVfpSave;
+ _G_fpuopVfp.CFPU_pfuncRestore = cskyVfpRestore;
return (&_G_fpuopVfp);
}
diff --git a/SylixOS/arch/csky/fpu/fpu/cskyVfp.h b/SylixOS/arch/csky/fpu/fpu/cskyVfp.h
index ad5f2fd..2702a15 100644
--- a/SylixOS/arch/csky/fpu/fpu/cskyVfp.h
+++ b/SylixOS/arch/csky/fpu/fpu/cskyVfp.h
@@ -27,6 +27,9 @@
PCSKY_FPU_OP cskyVfpPrimaryInit(CPCHAR pcMachineName, CPCHAR pcFpuName);
VOID cskyVfpSecondaryInit(CPCHAR pcMachineName, CPCHAR pcFpuName);
+UINT32 cskyVfpGetFESR(VOID);
+VOID cskyVfpSetFESR(UINT32 uiFESR);
+
#endif /* __ARCH_CSKYVFP_H */
/*********************************************************************************************************
END
diff --git a/SylixOS/arch/csky/fpu/fpu/cskyVfpAsm.S b/SylixOS/arch/csky/fpu/fpu/cskyVfpAsm.S
index b156c28..5d9567e 100644
--- a/SylixOS/arch/csky/fpu/fpu/cskyVfpAsm.S
+++ b/SylixOS/arch/csky/fpu/fpu/cskyVfpAsm.S
@@ -32,11 +32,55 @@
FILE_BEGIN()
EXPORT_LABEL(cskyVfpInit)
- EXPORT_LABEL(cskyVfpEnable)
- EXPORT_LABEL(cskyVfpDisable)
- EXPORT_LABEL(cskyVfpIsEnable)
EXPORT_LABEL(cskyVfpSave)
EXPORT_LABEL(cskyVfpRestore)
+ EXPORT_LABEL(cskyVfpGetFESR)
+ EXPORT_LABEL(cskyVfpSetFESR)
+
+;/*********************************************************************************************************
+; FCR 配置
+;*********************************************************************************************************/
+
+#define FCR_FM (0 << 27) /* 将非规格化数刷成有符号零 */
+#define FCR_RM (0 << 24) /* 舍入到最接近值 */
+
+#if LW_CFG_CPU_FPU_IDE > 0
+#define FCR_IDE (1 << 5)
+#else
+#define FCR_IDE 0
+#endif
+
+#if LW_CFG_CPU_FPU_IXE > 0
+#define FCR_IXE (1 << 4)
+#else
+#define FCR_IXE 0
+#endif
+
+#if LW_CFG_CPU_FPU_UFE > 0
+#define FCR_UFE (1 << 3)
+#else
+#define FCR_UFE 0
+#endif
+
+#if LW_CFG_CPU_FPU_OFE > 0
+#define FCR_OFE (1 << 2)
+#else
+#define FCR_OFE 0
+#endif
+
+#if LW_CFG_CPU_FPU_DZE > 0
+#define FCR_DZE (1 << 1)
+#else
+#define FCR_DZE 0
+#endif
+
+#if LW_CFG_CPU_FPU_IOE > 0
+#define FCR_IOE (1 << 0)
+#else
+#define FCR_IOE 0
+#endif
+
+#define FCR_CONFIG (FCR_FM | FCR_RM |FCR_IDE | FCR_IXE | FCR_UFE | FCR_OFE | FCR_DZE | FCR_IOE)
;/*********************************************************************************************************
; 宏定义
@@ -73,24 +117,13 @@ MACRO_DEF(FPU_REG_SAVE fr, tmp, base, offsetl, offseth)
#endif
;/*********************************************************************************************************
-; 使能 FPU
-;*********************************************************************************************************/
-
-MACRO_DEF(ENABLE_FPU)
- MFCR A1 , CR<1, 2>
- ORI A1 , A1 , FCR_ENABLE
- MTCR A1 , CR<1, 2>
- MACRO_END()
-
-;/*********************************************************************************************************
; 初始化 FPU
;*********************************************************************************************************/
FUNC_DEF(cskyVfpInit)
- MFCR A1 , CR<1, 2> ;/* 记录原 FPU 状态 */
+ MOVI A0 , FCR_CONFIG ;/* 设置 FPU 寄存器 */
+ MTCR A0 , CR<1, 2>
- ENABLE_FPU ;/* 使能 FPU */
-
MOVI A0 , 0
FMTVRL FR0 , A0 ;/* 清零 FPU 寄存器 */
@@ -135,41 +168,6 @@ FUNC_DEF(cskyVfpInit)
FUNC_END(cskyVfpInit)
;/*********************************************************************************************************
-; 使能 FPU
-;*********************************************************************************************************/
-
-FUNC_DEF(cskyVfpEnable)
- ENABLE_FPU ;/* 使能 FPU */
- RTS
- FUNC_END(cskyVfpEnable)
-
-;/*********************************************************************************************************
-; 禁能 FPU
-;*********************************************************************************************************/
-
-FUNC_DEF(cskyVfpDisable)
- MFCR A0 , CR<1, 2>
- MOVI A1 , FCR_ENABLE
- ANDN A0 , A1
- MTCR A0 , CR<1, 2>
- RTS
- FUNC_END(cskyVfpDisable)
-
-;/*********************************************************************************************************
-; 判断 FPU 是否使能
-;*********************************************************************************************************/
-
-FUNC_DEF(cskyVfpIsEnable)
- MFCR A1 , CR<1, 2>
- ANDI A1 , A1 , FCR_ENABLE
- BEZ A1 , 1f
- MOVI A0 , 1
-1:
- MOVI A0 , 0
- RTS
- FUNC_END(cskyVfpIsEnable)
-
-;/*********************************************************************************************************
; 保存 FPU 寄存器
;*********************************************************************************************************/
@@ -195,6 +193,7 @@ FUNC_DEF(cskyVfpSave)
FPU_REG_SAVE FR15, A1, A0, FPU_OFFSET_REG(15)
#else
+
FPU_REG_SAVE FR0 , A1, A0, FPU_OFFSET_REG_LO(0), FPU_OFFSET_REG_HI(0)
FPU_REG_SAVE FR1 , A1, A0, FPU_OFFSET_REG_LO(1), FPU_OFFSET_REG_HI(1)
FPU_REG_SAVE FR2 , A1, A0, FPU_OFFSET_REG_LO(2), FPU_OFFSET_REG_HI(2)
@@ -216,7 +215,7 @@ FUNC_DEF(cskyVfpSave)
MFCR A1 , CR<1, 2>
ST.W A1 , (A0 , FPU_OFFSET_FCR) ;/* 保存 FCR 状态寄存器 */
-
+
MFCR A1 , CR<2, 2>
ST.W A1 , (A0 , FPU_OFFSET_FESR) ;/* 保存 FECR 状态寄存器 */
@@ -228,8 +227,6 @@ FUNC_DEF(cskyVfpSave)
;*********************************************************************************************************/
FUNC_DEF(cskyVfpRestore)
- ENABLE_FPU ;/* 使能 FPU */
-
LD.W A1 , (A0 , FPU_OFFSET_FESR) ;/* 恢复 FECR 状态寄存器 */
MTCR A1 , CR<2, 2>
@@ -270,6 +267,7 @@ FUNC_DEF(cskyVfpRestore)
FPU_REG_RESTORE FR13, A1, A0, FPU_OFFSET_REG_LO(13), FPU_OFFSET_REG_HI(13)
FPU_REG_RESTORE FR14, A1, A0, FPU_OFFSET_REG_LO(14), FPU_OFFSET_REG_HI(14)
FPU_REG_RESTORE FR15, A1, A0, FPU_OFFSET_REG_LO(15), FPU_OFFSET_REG_HI(15)
+
#endif
LD.W A1 , (A0 , FPU_OFFSET_FCR) ;/* 恢复 FCR 状态寄存器 */
@@ -278,6 +276,24 @@ FUNC_DEF(cskyVfpRestore)
RTS
FUNC_END(cskyVfpRestore)
+;/*********************************************************************************************************
+; 获得 FESR 寄存器
+;*********************************************************************************************************/
+
+FUNC_DEF(cskyVfpGetFESR)
+ MFCR A0 , CR<2, 2>
+ RTS
+ FUNC_END(cskyVfpGetFESR)
+
+;/*********************************************************************************************************
+; 设置 FESR 寄存器
+;*********************************************************************************************************/
+
+FUNC_DEF(cskyVfpSetFESR)
+ MTCR A0 , CR<2, 2>
+ RTS
+ FUNC_END(cskyVfpSetFESR)
+
FILE_END()
#endif
diff --git a/SylixOS/arch/csky/mm/mmu/cskyMmu.c b/SylixOS/arch/csky/mm/mmu/cskyMmu.c
index ef26de1..b4a07cc 100644
--- a/SylixOS/arch/csky/mm/mmu/cskyMmu.c
+++ b/SylixOS/arch/csky/mm/mmu/cskyMmu.c
@@ -611,6 +611,7 @@ VOID cskyMmuInvalidateTLBMVA (addr_t ulAddr)
cskyEntryLo1Write(0);
cskyEntryHiWrite(CSKY_UNIQUE_ENTRYHI(iIndex));
cskyTlbWriteIndexed();
+
} else {
break;
}
diff --git a/SylixOS/arch/mips/backtrace/mipsBacktrace.c b/SylixOS/arch/mips/backtrace/mipsBacktrace.c
index c0f7e64..be1f3a3 100644
--- a/SylixOS/arch/mips/backtrace/mipsBacktrace.c
+++ b/SylixOS/arch/mips/backtrace/mipsBacktrace.c
@@ -43,6 +43,9 @@
#define INST_OP_MASK 0xffff0000
#define INST_OFFSET_MASK 0x0000ffff
+
+#define IS_UNALIGN_RA(p) ((addr_t)(p) & 0x3)
+#define IS_UNALIGN_SP(p) ((addr_t)(p) & (ARCH_REG_SIZE - 1))
/*********************************************************************************************************
** 函数名称: getEndStack
** 功能描述: 获得堆栈结束地址
@@ -105,12 +108,16 @@ int backtrace (void **array, int size)
if (stack_size != 0) {
break;
}
+
} else if (inst == JR_RA_INST) { /* 遇上了 JR RA 指令 */
return (cnt); /* 直接返回 */
}
}
sp = (unsigned long *)((unsigned long)low_stack + stack_size); /* 调用者的 SP */
+ if (IS_UNALIGN_SP(sp)) {
+ return (cnt);
+ }
if (sp[-1] != ((unsigned long)ra)) { /* backtrace 保存的 RA 不对 */
return (cnt);
@@ -131,8 +138,8 @@ int backtrace (void **array, int size)
stack_size = 0;
for (addr = (MIPS_INSTRUCTION *)ra; /* 在返回的位置向上找 */
- (ra_offset == 0) || (stack_size == 0);
- addr--) {
+ stack_size == 0; /* 堆栈开辟指令是函数的第一条 */
+ addr--) { /* 指令, 找到 stack_size 便跳出*/
inst = *addr;
switch (inst & INST_OP_MASK) {
@@ -151,8 +158,12 @@ int backtrace (void **array, int size)
}
}
+ if (!ra_offset) { /* 叶子函数, 没有保存 RA */
+ break; /* 无法继续分析 */
+ }
+
ra = (unsigned long *)sp[ra_offset >> LONGLOG]; /* 取出保存的 RA */
- if (ra == 0) { /* 最后一层无返回函数 */
+ if (ra == 0 || IS_UNALIGN_RA(ra)) { /* 最后一层无返回函数 */
break;
}
@@ -166,6 +177,10 @@ int backtrace (void **array, int size)
sp = fp; /* 以 FP 为准 */
}
+ if (IS_UNALIGN_SP(sp)) {
+ break;
+ }
+
if ((sp >= end_stack) || (sp <= low_stack)) { /* SP 不合法 */
break;
}
diff --git a/SylixOS/arch/mips/common/mipsExc.c b/SylixOS/arch/mips/common/mipsExc.c
index 42e070f..ec98a83 100644
--- a/SylixOS/arch/mips/common/mipsExc.c
+++ b/SylixOS/arch/mips/common/mipsExc.c
@@ -22,6 +22,7 @@
#define __SYLIXOS_KERNEL
#include "SylixOS.h"
#include "dtrace.h"
+#include "arch/mips/param/mipsParam.h"
#include "arch/mips/common/cp0/mipsCp0.h"
#include "arch/mips/common/unaligned/mipsUnaligned.h"
#if LW_CFG_VMM_EN > 0
@@ -244,6 +245,21 @@ static VOID archTlbStoreExceptHandle (addr_t ulRetAddr, addr_t ulAbortAddr)
}
}
/*********************************************************************************************************
+** 函数名称: archUnalignedHandle
+** 功能描述: 非对齐内存访问异常处理
+** 输 入 : pabtctx abort 上下文
+** 输 出 : NONE
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static VOID archUnalignedHandle (PLW_VMM_ABORT_CTX pabtctx)
+{
+ mipsUnalignedHandle(&pabtctx->ABTCTX_archRegCtx,
+ &pabtctx->ABTCTX_abtInfo);
+
+ API_VmmAbortReturn(pabtctx);
+}
+/*********************************************************************************************************
** 函数名称: archAddrLoadExceptHandle
** 功能描述: Address load or ifetch 异常处理
** 输 入 : ulRetAddr 返回地址
@@ -257,6 +273,7 @@ static VOID archAddrLoadExceptHandle (addr_t ulRetAddr, addr_t ulAbortAddr, A
{
PLW_CLASS_TCB ptcbCur;
LW_VMM_ABORT abtInfo;
+ MIPS_PARAM *param = archKernelParamGet();
LW_TCB_GET_CUR(ptcbCur);
@@ -270,11 +287,6 @@ static VOID archAddrLoadExceptHandle (addr_t ulRetAddr, addr_t ulAbortAddr, A
* TODO: 由于现在未使用用户模式, 所以第三种情况暂不用处理
*/
-<<<<<<< 1b323980847b6cfbd0ceb2e812beac4659aa6762
- abtInfo.VMABT_uiMethod = LW_VMM_ABORT_METHOD_READ;
- abtInfo.VMABT_uiType = mipsUnalignedHandle(pregctx, ulAbortAddr);
- if (abtInfo.VMABT_uiType) {
-=======
abtInfo.VMABT_uiMethod = BUS_ADRALN;
abtInfo.VMABT_uiType = LW_VMM_ABORT_TYPE_BUS;
@@ -282,7 +294,6 @@ static VOID archAddrLoadExceptHandle (addr_t ulRetAddr, addr_t ulAbortAddr, A
API_VmmAbortIsrEx(ulRetAddr, ulAbortAddr, &abtInfo, ptcbCur, archUnalignedHandle);
} else {
->>>>>>> Fixed Loongson-2G/2H/3A/3B ll/sc and lld/scd is very weak ordering bug.
API_VmmAbortIsr(ulRetAddr, ulAbortAddr, &abtInfo, ptcbCur);
}
}
@@ -300,6 +311,7 @@ static VOID archAddrStoreExceptHandle (addr_t ulRetAddr, addr_t ulAbortAddr,
{
PLW_CLASS_TCB ptcbCur;
LW_VMM_ABORT abtInfo;
+ MIPS_PARAM *param = archKernelParamGet();
LW_TCB_GET_CUR(ptcbCur);
@@ -810,6 +822,7 @@ VOID archExceptionHandle (ARCH_REG_CTX *pregctx)
pfuncExceptHandle = _G_mipsExceptHandle[ulExcCode];
if (pfuncExceptHandle == LW_NULL) {
_BugFormat(LW_TRUE, LW_TRUE, "Unknown exception: %d\r\n", ulExcCode);
+
} else {
pfuncExceptHandle(pregctx->REG_ulCP0Epc, pregctx->REG_ulCP0BadVAddr, pregctx);
}
diff --git a/SylixOS/arch/mips/common/unaligned/mipsUnaligned.c b/SylixOS/arch/mips/common/unaligned/mipsUnaligned.c
index b77f014..188f87a 100644
--- a/SylixOS/arch/mips/common/unaligned/mipsUnaligned.c
+++ b/SylixOS/arch/mips/common/unaligned/mipsUnaligned.c
@@ -102,7 +102,6 @@
#include "arch/mips/inc/asm-eva.h"
#include "arch/mips/inc/inst.h"
#include "arch/mips/inc/branch.h"
-#include "arch/mips/param/mipsParam.h"
#if LW_CFG_CPU_FPU_EN > 0
#include "arch/mips/fpu/emu/mipsFpuEmu.h"
#if LW_CFG_MIPS_HAS_MSA_INSTR > 0
@@ -891,8 +890,8 @@ do { \
#define StoreWE(addr, value, res) _StoreW(addr, value, res, user)
#define StoreDW(addr, value, res) _StoreDW(addr, value, res)
-static int emulate_load_store_insn(ARCH_REG_CTX *regs,
- void __user *addr, unsigned int __user *pc)
+static void emulate_load_store_insn(ARCH_REG_CTX *regs,
+ void __user *addr, unsigned int __user *pc, PLW_VMM_ABORT pabtInfo)
{
union mips_instruction insn;
unsigned long value;
@@ -1359,32 +1358,36 @@ static int emulate_load_store_insn(ARCH_REG_CTX *regs,
unaligned_instructions++;
#endif
- return (0);
+ pabtInfo->VMABT_uiType = LW_VMM_ABORT_TYPE_NOINFO;
+ return;
fault:
/* roll back jump/branch */
regs->cp0_epc = origpc;
regs->regs[31] = orig31;
- return (LW_VMM_ABORT_TYPE_TERMINAL);
+ pabtInfo->VMABT_uiType = LW_VMM_ABORT_TYPE_TERMINAL;
+ return;
sigbus:
- return (LW_VMM_ABORT_TYPE_BUS);
+ pabtInfo->VMABT_uiType = LW_VMM_ABORT_TYPE_BUS;
+ pabtInfo->VMABT_uiMethod = BUS_ADRALN;
+ return;
sigill:
- return (LW_VMM_ABORT_TYPE_UNDEF);
+ pabtInfo->VMABT_uiType = LW_VMM_ABORT_TYPE_UNDEF;
+ pabtInfo->VMABT_uiMethod = LW_VMM_ABORT_METHOD_EXEC;
}
/*********************************************************************************************************
** 函数名称: mipsUnalignedHandle
** 功能描述: MIPS 非对齐处理
** 输 入 : pregctx 寄存器上下文
-** ulAbortAddr 终止地址
-** 输 出 : 终止类型
+** pabtInfo 终止信息
+** 输 出 : NONE
** 全局变量:
** 调用模块:
*********************************************************************************************************/
-ULONG mipsUnalignedHandle (ARCH_REG_CTX *pregctx, addr_t ulAbortAddr)
+VOID mipsUnalignedHandle (ARCH_REG_CTX *pregctx, PLW_VMM_ABORT pabtInfo)
{
- MIPS_PARAM *param = archKernelParamGet();
MIPS_INSTRUCTION *pc;
/*
@@ -1401,10 +1404,12 @@ ULONG mipsUnalignedHandle (ARCH_REG_CTX *pregctx, addr_t ulAbortAddr)
* Do branch emulation only if we didn't forward the exception.
* This is all so but ugly ...
*/
- return (emulate_load_store_insn(pregctx, (VOID *)ulAbortAddr, pc));
+ emulate_load_store_insn(pregctx, (VOID *)pregctx->REG_ulCP0BadVAddr, pc, pabtInfo);
+ return;
sigbus:
- return (LW_VMM_ABORT_TYPE_BUS);
+ pabtInfo->VMABT_uiType = LW_VMM_ABORT_TYPE_BUS;
+ pabtInfo->VMABT_uiMethod = BUS_ADRALN;
}
/*********************************************************************************************************
END
diff --git a/SylixOS/arch/mips/common/unaligned/mipsUnaligned.h b/SylixOS/arch/mips/common/unaligned/mipsUnaligned.h
index f0ce85c..a875a70 100644
--- a/SylixOS/arch/mips/common/unaligned/mipsUnaligned.h
+++ b/SylixOS/arch/mips/common/unaligned/mipsUnaligned.h
@@ -22,7 +22,7 @@
#ifndef __ARCH_MIPSUNALIGNED_H
#define __ARCH_MIPSUNALIGNED_H
-ULONG mipsUnalignedHandle(ARCH_REG_CTX *pregctx, addr_t ulAbortAddr);
+VOID mipsUnalignedHandle(ARCH_REG_CTX *pregctx, PLW_VMM_ABORT pabtInfo);
#endif /* __ARCH_MIPSUNALIGNED_H */
/*********************************************************************************************************
diff --git a/SylixOS/arch/mips/dsp/hr2vector/mipsHr2Vector.c b/SylixOS/arch/mips/dsp/hr2vector/mipsHr2Vector.c
index 8f83d36..53e756b 100644
--- a/SylixOS/arch/mips/dsp/hr2vector/mipsHr2Vector.c
+++ b/SylixOS/arch/mips/dsp/hr2vector/mipsHr2Vector.c
@@ -52,9 +52,22 @@ extern VOID mipsHr2VectorRestore(ARCH_DSP_CTX *pdspctx);
static VOID mipsHr2VectorCtxShow (INT iFd, ARCH_DSP_CTX *pdspctx)
{
#if (LW_CFG_DEVICE_EN > 0) && (LW_CFG_FIO_LIB_EN > 0)
- /*
- * Not in opensoure version
- */
+ HR2_VECTOR_CTX *phr2VectorCtx = &pdspctx->DSPCTX_hr2VectorCtx;
+ INT i;
+
+ fdprintf(iFd, "VCCR = 0x%08x\n", phr2VectorCtx->HR2VECCTX_uiVccr);
+
+ for (i = 0; i < HR2_VECTOR_REG_NR; i++) {
+ fdprintf(iFd, "Z%02d = 0x%08x%08x0x%08x%08x0x%08x%08x0x%08x%08x\n", i,
+ phr2VectorCtx->HR2VECCTX_vectorRegs[i].val32[0],
+ phr2VectorCtx->HR2VECCTX_vectorRegs[i].val32[1],
+ phr2VectorCtx->HR2VECCTX_vectorRegs[i].val32[2],
+ phr2VectorCtx->HR2VECCTX_vectorRegs[i].val32[3],
+ phr2VectorCtx->HR2VECCTX_vectorRegs[i].val32[4],
+ phr2VectorCtx->HR2VECCTX_vectorRegs[i].val32[5],
+ phr2VectorCtx->HR2VECCTX_vectorRegs[i].val32[6],
+ phr2VectorCtx->HR2VECCTX_vectorRegs[i].val32[7]);
+ }
#endif
}
/*********************************************************************************************************
@@ -67,9 +80,10 @@ static VOID mipsHr2VectorCtxShow (INT iFd, ARCH_DSP_CTX *pdspctx)
*********************************************************************************************************/
static VOID mipsHr2VectorEnableTask (PLW_CLASS_TCB ptcbCur)
{
- /*
- * Not in opensoure version
- */
+ ARCH_REG_CTX *pregctx;
+
+ pregctx = &ptcbCur->TCB_archRegCtx;
+ pregctx->REG_ulCP0Status |= ST0_CU2;
}
/*********************************************************************************************************
** 函数名称: mipsHr2VectorPrimaryInit
diff --git a/SylixOS/arch/mips/dsp/hr2vector/mipsHr2VectorAsm.S b/SylixOS/arch/mips/dsp/hr2vector/mipsHr2VectorAsm.S
index b5df09c..659f0e2 100644
--- a/SylixOS/arch/mips/dsp/hr2vector/mipsHr2VectorAsm.S
+++ b/SylixOS/arch/mips/dsp/hr2vector/mipsHr2VectorAsm.S
@@ -38,14 +38,89 @@
EXPORT_LABEL(mipsHr2VectorSave)
EXPORT_LABEL(mipsHr2VectorRestore)
+/*********************************************************************************************************
+ 向量控制寄存器
+*********************************************************************************************************/
+
+#define CP2_VIR $0
+#define CP2_VFCR $1
+#define CP2_VENR $2
+#define CP2_VFR $3
+#define CP2_VSCR $4
+#define CP2_VCCR $8
+
+;/*********************************************************************************************************
+; VCCR 偏移
+;*********************************************************************************************************/
+
+#define VECTOR_OFFSET_VCCR (32 * (256 / 8)) /* 前面有 32 个 256 位宽寄存器 */
+
+;/*********************************************************************************************************
+; VSCR 寄存器相关定义
+;*********************************************************************************************************/
+
+#define VECTOR_VSCR_FS (1 << 8) /* 非规格化结果被置为 0 */
+
+;/*********************************************************************************************************
+; 使能向量运算单元(只会破坏 T0 寄存器)
+;*********************************************************************************************************/
+
+MACRO_DEF(ENABLE_VECTOR)
+ MFC0_EHB(T0, CP0_STATUS)
+ OR T0 , T0 , ST0_CU2
+ MTC0_EHB(T0, CP0_STATUS)
+ MACRO_END()
+
;/*********************************************************************************************************
; 初始化向量运算单元
;*********************************************************************************************************/
FUNC_DEF(mipsHr2VectorInit)
- ;/*
- ; * Not in opensource version
- ; */
+ MFC0_EHB(T1, CP0_STATUS) ;/* T1 = 原 VECTOR 开关状态 */
+
+ ENABLE_VECTOR ;/* 使能 VECTOR */
+
+ PTR_LA T0 , mipsHr2VectorRegZero
+
+ VLDDQ $z0 , 0(T0) ;/* 清零 VECTOR 寄存器 */
+ VLDDQ $z1 , 0(T0)
+ VLDDQ $z2 , 0(T0)
+ VLDDQ $z3 , 0(T0)
+ VLDDQ $z4 , 0(T0)
+ VLDDQ $z5 , 0(T0)
+ VLDDQ $z6 , 0(T0)
+ VLDDQ $z7 , 0(T0)
+ VLDDQ $z8 , 0(T0)
+ VLDDQ $z9 , 0(T0)
+ VLDDQ $z10 , 0(T0)
+ VLDDQ $z11 , 0(T0)
+ VLDDQ $z12 , 0(T0)
+ VLDDQ $z13 , 0(T0)
+ VLDDQ $z14 , 0(T0)
+ VLDDQ $z15 , 0(T0)
+ VLDDQ $z16 , 0(T0)
+ VLDDQ $z17 , 0(T0)
+ VLDDQ $z18 , 0(T0)
+ VLDDQ $z19 , 0(T0)
+ VLDDQ $z20 , 0(T0)
+ VLDDQ $z21 , 0(T0)
+ VLDDQ $z22 , 0(T0)
+ VLDDQ $z23 , 0(T0)
+ VLDDQ $z24 , 0(T0)
+ VLDDQ $z25 , 0(T0)
+ VLDDQ $z26 , 0(T0)
+ VLDDQ $z27 , 0(T0)
+ VLDDQ $z28 , 0(T0)
+ VLDDQ $z29 , 0(T0)
+ VLDDQ $z30 , 0(T0)
+ VLDDQ $z31 , 0(T0)
+
+ CTC2_EHB(ZERO, CP2_VCCR) ;/* VCC 清零 */
+
+ LI T0 , VECTOR_VSCR_FS ;/* 非规格化结果被置为 0 */
+ CTC2_EHB(T0, CP2_VSCR)
+
+ MTC0_EHB(T1 , CP0_STATUS) ;/* 恢复原 VECTOR 开关状态 */
JR RA
NOP
FUNC_END(mipsHr2VectorInit)
@@ -55,9 +130,7 @@ FUNC_DEF(mipsHr2VectorInit)
;*********************************************************************************************************/
FUNC_DEF(mipsHr2VectorEnable)
- ;/*
- ; * Not in opensource version
- ; */
+ ENABLE_VECTOR ;/* 使能 VECTOR */
JR RA
NOP
FUNC_END(mipsHr2VectorEnable)
@@ -67,9 +140,9 @@ FUNC_DEF(mipsHr2VectorEnable)
;*********************************************************************************************************/
FUNC_DEF(mipsHr2VectorDisable)
- ;/*
- ; * Not in opensource version
- ; */
+ MFC0_EHB(T0, CP0_STATUS)
+ AND T0 , T0 , ~ST0_CU2
+ MTC0_EHB(T0, CP0_STATUS)
JR RA
NOP
FUNC_END(mipsHr2VectorDisable)
@@ -79,10 +152,13 @@ FUNC_DEF(mipsHr2VectorDisable)
;*********************************************************************************************************/
FUNC_DEF(mipsHr2VectorIsEnable)
- ;/*
- ; * Not in opensource version
- ; */
- MOV V0 , ZERO
+ MOV V0 , ZERO ;/* FALSE return value */
+ MFC0_EHB(T0, CP0_STATUS)
+ AND T0 , T0 , ST0_CU2 ;/* VECTOR enabled */
+ BEQ T0 , ZERO, 1f
+ NOP
+ LI V0 , 1 ;/* TRUE return value */
+1:
JR RA
NOP
FUNC_END(mipsHr2VectorIsEnable)
@@ -92,9 +168,46 @@ FUNC_DEF(mipsHr2VectorIsEnable)
;*********************************************************************************************************/
FUNC_DEF(mipsHr2VectorSave)
- ;/*
- ; * Not in opensource version
- ; */
+ ENABLE_VECTOR ;/* 使能 VECTOR */
+
+ VSTDQ $z0 , 0 (A0)
+ VSTDQ $z1 , 32 (A0)
+ VSTDQ $z2 , 64 (A0)
+ VSTDQ $z3 , 96 (A0)
+ VSTDQ $z4 , 128(A0)
+ VSTDQ $z5 , 160(A0)
+ VSTDQ $z6 , 192(A0)
+ VSTDQ $z7 , 224(A0)
+ VSTDQ $z8 , 256(A0)
+ VSTDQ $z9 , 288(A0)
+ VSTDQ $z10 , 320(A0)
+ VSTDQ $z11 , 352(A0)
+ VSTDQ $z12 , 384(A0)
+ VSTDQ $z13 , 416(A0)
+ VSTDQ $z14 , 448(A0)
+ VSTDQ $z15 , 480(A0)
+ VSTDQ $z16 , 512(A0)
+ VSTDQ $z17 , 544(A0)
+ VSTDQ $z18 , 576(A0)
+ VSTDQ $z19 , 608(A0)
+ VSTDQ $z20 , 640(A0)
+ VSTDQ $z21 , 672(A0)
+ VSTDQ $z22 , 704(A0)
+ VSTDQ $z23 , 736(A0)
+ VSTDQ $z24 , 768(A0)
+ VSTDQ $z25 , 800(A0)
+ VSTDQ $z26 , 832(A0)
+ VSTDQ $z27 , 864(A0)
+ VSTDQ $z28 , 896(A0)
+ VSTDQ $z29 , 928(A0)
+ VSTDQ $z30 , 960(A0)
+ VSTDQ $z31 , 992(A0)
+
+ CFC2_EHB(T1, CP2_VCCR)
+ SW T1 , VECTOR_OFFSET_VCCR(A0) ;/* 保存 VCCR 寄存器 */
+
+ EHB
+
JR RA
NOP
FUNC_END(mipsHr2VectorSave)
@@ -104,13 +217,57 @@ FUNC_DEF(mipsHr2VectorSave)
;*********************************************************************************************************/
FUNC_DEF(mipsHr2VectorRestore)
- ;/*
- ; * Not in opensource version
- ; */
+ ENABLE_VECTOR ;/* 使能 VECTOR */
+
+ VLDDQ $z0 , 0 (A0)
+ VLDDQ $z1 , 32 (A0)
+ VLDDQ $z2 , 64 (A0)
+ VLDDQ $z3 , 96 (A0)
+ VLDDQ $z4 , 128(A0)
+ VLDDQ $z5 , 160(A0)
+ VLDDQ $z6 , 192(A0)
+ VLDDQ $z7 , 224(A0)
+ VLDDQ $z8 , 256(A0)
+ VLDDQ $z9 , 288(A0)
+ VLDDQ $z10 , 320(A0)
+ VLDDQ $z11 , 352(A0)
+ VLDDQ $z12 , 384(A0)
+ VLDDQ $z13 , 416(A0)
+ VLDDQ $z14 , 448(A0)
+ VLDDQ $z15 , 480(A0)
+ VLDDQ $z16 , 512(A0)
+ VLDDQ $z17 , 544(A0)
+ VLDDQ $z18 , 576(A0)
+ VLDDQ $z19 , 608(A0)
+ VLDDQ $z20 , 640(A0)
+ VLDDQ $z21 , 672(A0)
+ VLDDQ $z22 , 704(A0)
+ VLDDQ $z23 , 736(A0)
+ VLDDQ $z24 , 768(A0)
+ VLDDQ $z25 , 800(A0)
+ VLDDQ $z26 , 832(A0)
+ VLDDQ $z27 , 864(A0)
+ VLDDQ $z28 , 896(A0)
+ VLDDQ $z29 , 928(A0)
+ VLDDQ $z30 , 960(A0)
+ VLDDQ $z31 , 992(A0)
+
+ LW T1 , VECTOR_OFFSET_VCCR(A0) ;/* 恢复 VCCR 寄存器 */
+ CTC2_EHB(T1, CP2_VCCR)
+
JR RA
NOP
FUNC_END(mipsHr2VectorRestore)
+;/*********************************************************************************************************
+; 用于向量寄存器清零
+;*********************************************************************************************************/
+
+ SECTION(.bss)
+ .balign 32
+LINE_LABEL(mipsHr2VectorRegZero)
+ .space 32
+
FILE_END()
#endif
diff --git a/SylixOS/arch/mips/elf/mipsElf32.c b/SylixOS/arch/mips/elf/mipsElf32.c
index 7efa78b..fd48ec9 100644
--- a/SylixOS/arch/mips/elf/mipsElf32.c
+++ b/SylixOS/arch/mips/elf/mipsElf32.c
@@ -153,6 +153,8 @@ static INT mipsElfLO16RelocateRel (LW_LD_EXEC_MODULE *pmodule,
** 输 出 : ERROR_NONE 表示没有错误, PX_ERROR 表示错误
** 全局变量:
** 调用模块:
+** 注 意 : R_MIPS_HI16 与 R_MIPS_LO16 为成对出现, 确保内存无泄漏.
+** TODO: 如果 ELF 文件损坏, 可能发生内存泄漏.
*********************************************************************************************************/
INT archElfRelocateRel (PVOID pmodule,
Elf_Rel *prel,
diff --git a/SylixOS/arch/mips/mm/cache/hr2/mipsCacheHr2.c b/SylixOS/arch/mips/mm/cache/hr2/mipsCacheHr2.c
index 3fbf53f..5f564ba 100644
--- a/SylixOS/arch/mips/mm/cache/hr2/mipsCacheHr2.c
+++ b/SylixOS/arch/mips/mm/cache/hr2/mipsCacheHr2.c
@@ -78,9 +78,27 @@ static VOID hr2BranchPredictorInvalidate (VOID)
*********************************************************************************************************/
VOID hr2CacheFlushAll (VOID)
{
- /*
- * Not in opensource version
- */
+ REGISTER PVOID pvAddr;
+
+ __asm__ __volatile__(
+ " .set push \n"
+ " .set noreorder \n"
+ " li %[addr], 0x80000000 \n" /* KSEG0 */
+ "1: cache 0, 0(%[addr]) \n" /* Flush L1 ICACHE */
+ " cache 0, 1(%[addr]) \n"
+ " cache 0, 2(%[addr]) \n"
+ " cache 0, 3(%[addr]) \n"
+ " cache 1, 0(%[addr]) \n" /* Flush L1 DCACHE */
+ " cache 1, 1(%[addr]) \n"
+ " cache 1, 2(%[addr]) \n"
+ " cache 1, 3(%[addr]) \n"
+ " addiu %[sets], %[sets], -1 \n"
+ " bnez %[sets], 1b \n"
+ " addiu %[addr], %[addr], 0x20 \n"
+ " sync \n"
+ " .set pop \n"
+ : [addr] "=&r" (pvAddr)
+ : [sets] "r" (64)); /* 每路 64 组 */
}
/*********************************************************************************************************
** 函数名称: hr2CacheEnable
@@ -92,9 +110,20 @@ VOID hr2CacheFlushAll (VOID)
*********************************************************************************************************/
static INT hr2CacheEnable (LW_CACHE_TYPE cachetype)
{
- /*
- * Not in opensource version
- */
+ if (cachetype == INSTRUCTION_CACHE) {
+ if (LW_CPU_GET_CUR_ID() == 0) {
+ _G_iCacheStatus |= L1_CACHE_I_EN;
+ }
+ } else {
+ if (LW_CPU_GET_CUR_ID() == 0) {
+ _G_iCacheStatus |= L1_CACHE_D_EN;
+ }
+ }
+
+ if (_G_iCacheStatus == L1_CACHE_EN) {
+ hr2CacheEnableHw();
+ hr2BranchPredictionEnable();
+ }
return (ERROR_NONE);
}
@@ -108,9 +137,22 @@ static INT hr2CacheEnable (LW_CACHE_TYPE cachetype)
*********************************************************************************************************/
static INT hr2CacheDisable (LW_CACHE_TYPE cachetype)
{
- /*
- * Not in opensource version
- */
+ if (cachetype == INSTRUCTION_CACHE) {
+ if (LW_CPU_GET_CUR_ID() == 0) {
+ _G_iCacheStatus &= ~L1_CACHE_I_EN;
+ }
+ } else {
+ if (LW_CPU_GET_CUR_ID() == 0) {
+ _G_iCacheStatus &= ~L1_CACHE_D_EN;
+ }
+ }
+
+ if (_G_iCacheStatus == L1_CACHE_DIS) {
+ /*
+ * 不能关闭 CACHE
+ */
+ hr2BranchPredictionDisable();
+ }
return (ERROR_NONE);
}
diff --git a/SylixOS/arch/mips/mm/cache/hr2/mipsCacheHr2Asm.S b/SylixOS/arch/mips/mm/cache/hr2/mipsCacheHr2Asm.S
index 3ba8e54..2ec6ff0 100644
--- a/SylixOS/arch/mips/mm/cache/hr2/mipsCacheHr2Asm.S
+++ b/SylixOS/arch/mips/mm/cache/hr2/mipsCacheHr2Asm.S
@@ -38,9 +38,18 @@
;*********************************************************************************************************/
FUNC_DEF(hr2CacheEnableHw)
- ;/*
- ; * Not in opensource version
- ; */
+ MFC0_EHB(T0, CP0_CONFIG)
+ ANDI T0 , T0 , CONF_CM_CMASK
+ LI T1 , 6
+ BEQ T0 , T1 , 1f
+ NOP
+
+ MFC0_EHB(T0, CP0_CONFIG)
+ AND T0 , T0 , ~CONF_CM_CMASK
+ ORI T0 , 6
+ MTC0_EHB(T0, CP0_CONFIG)
+
+1:
JR RA
NOP
FUNC_END(hr2CacheEnableHw)
diff --git a/SylixOS/arch/mips/mm/mmu/mipsMmuCommon.c b/SylixOS/arch/mips/mm/mmu/mipsMmuCommon.c
index 977fa72..1846ba9 100644
--- a/SylixOS/arch/mips/mm/mmu/mipsMmuCommon.c
+++ b/SylixOS/arch/mips/mm/mmu/mipsMmuCommon.c
@@ -145,6 +145,7 @@ VOID mipsMmuInvalidateTLBMVA (addr_t ulAddr)
mipsCp0EntryLo1Write(0);
mipsCp0EntryHiWrite(MIPS_UNIQUE_ENTRYHI(iIndex));
MIPS_MMU_TLB_WRITE_INDEX();
+
} else {
break;
}
@@ -263,6 +264,7 @@ ULONG mipsMmuTlbLoadStoreExcHandle (addr_t ulAbortAddr, BOOL bStore)
bIsEntryLo1 = !!(ulAbortAddr & (1 << LW_CFG_VMM_PAGE_SHIFT));
if (bIsEntryLo1) {
ulEntryLo = mipsCp0EntryLo1Read();
+
} else {
ulEntryLo = mipsCp0EntryLo0Read();
}
@@ -274,6 +276,7 @@ ULONG mipsMmuTlbLoadStoreExcHandle (addr_t ulAbortAddr, BOOL bStore)
* 可能这是 Loongson-1B 处理器的 BUG, 但不响应程序继续运行
*/
ulAbortType = 0;
+
} else {
/*
* TLB 无效异常(正确情况)
@@ -291,6 +294,7 @@ ULONG mipsMmuTlbLoadStoreExcHandle (addr_t ulAbortAddr, BOOL bStore)
*/
_DebugHandle(__ERRORMESSAGE_LEVEL, "TLB refill error.\r\n");
ulAbortType = LW_VMM_ABORT_TYPE_FATAL_ERROR;
+
} else {
/*
* 如果 TLB 重填异常不是发生异常里, 忽略之, 也不进行 TLB 重填
diff --git a/SylixOS/arch/ppc/common/e500/ppcExcE500.c b/SylixOS/arch/ppc/common/e500/ppcExcE500.c
index 7f5ee4c..97d8535 100644
--- a/SylixOS/arch/ppc/common/e500/ppcExcE500.c
+++ b/SylixOS/arch/ppc/common/e500/ppcExcE500.c
@@ -29,6 +29,7 @@
#define __SYLIXOS_PPC_E500__
#define __SYLIXOS_PPC_E500MC__
#include "arch/ppc/arch_e500.h"
+#include "arch/ppc/param/ppcParam.h"
#if LW_CFG_VMM_EN > 0
#include "arch/ppc/mm/mmu/e500/ppcMmuE500.h"
#endif
@@ -192,6 +193,21 @@ VOID archE500InstructionStorageExceptionHandle (addr_t ulRetAddr)
}
}
/*********************************************************************************************************
+** 函数名称: archE500UnalignedHandle
+** 功能描述: 非对齐内存访问异常处理
+** 输 入 : pabtctx abort 上下文
+** 输 出 : NONE
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static VOID archE500UnalignedHandle (PLW_VMM_ABORT_CTX pabtctx)
+{
+ ppcUnalignedHandle(&pabtctx->ABTCTX_archRegCtx,
+ &pabtctx->ABTCTX_abtInfo);
+
+ API_VmmAbortReturn(pabtctx);
+}
+/*********************************************************************************************************
** 函数名称: archE500AlignmentExceptionHandle
** 功能描述: 非对齐异常处理
** 输 入 : NONE
diff --git a/SylixOS/arch/ppc/common/ppcContext.c b/SylixOS/arch/ppc/common/ppcContext.c
index 158a12a..8b5fe93 100644
--- a/SylixOS/arch/ppc/common/ppcContext.c
+++ b/SylixOS/arch/ppc/common/ppcContext.c
@@ -151,8 +151,9 @@ VOID archTaskCtxSetFp (PLW_STACK pstkDest,
* add fp, sp, #4
*/
pfpctx->FP_uiFp = pregctxSrc->REG_uiFp;
- pfpctx->FP_uiLr = pregctxSrc->REG_uiLr;
+ pfpctx->FP_uiLr = pregctxSrc->REG_uiPc;
+ pregctxDest->REG_uiLr = pregctxSrc->REG_uiPc;
pregctxDest->REG_uiFp = (ARCH_REG_T)&pfpctx->FP_uiLr;
}
/*********************************************************************************************************
diff --git a/SylixOS/arch/ppc/common/ppcExc.c b/SylixOS/arch/ppc/common/ppcExc.c
index cba1022..15ad8d0 100644
--- a/SylixOS/arch/ppc/common/ppcExc.c
+++ b/SylixOS/arch/ppc/common/ppcExc.c
@@ -22,6 +22,7 @@
#include "SylixOS.h"
#include "dtrace.h"
#include "ppcSpr.h"
+#include "arch/ppc/param/ppcParam.h"
#if LW_CFG_VMM_EN > 0
#include "arch/ppc/mm/mmu/common/ppcMmu.h"
#endif
@@ -238,6 +239,21 @@ VOID archInstructionStorageExceptionHandle (addr_t ulRetAddr)
}
}
/*********************************************************************************************************
+** 函数名称: archUnalignedHandle
+** 功能描述: 非对齐内存访问异常处理
+** 输 入 : pabtctx abort 上下文
+** 输 出 : NONE
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static VOID archUnalignedHandle (PLW_VMM_ABORT_CTX pabtctx)
+{
+ ppcUnalignedHandle(&pabtctx->ABTCTX_archRegCtx,
+ &pabtctx->ABTCTX_abtInfo);
+
+ API_VmmAbortReturn(pabtctx);
+}
+/*********************************************************************************************************
** 函数名称: archAlignmentExceptionHandle
** 功能描述: 非对齐异常处理
** 输 入 : NONE
diff --git a/SylixOS/arch/ppc/common/unaligned/porting.h b/SylixOS/arch/ppc/common/unaligned/porting.h
index 6c6a7da..a2c3232 100644
--- a/SylixOS/arch/ppc/common/unaligned/porting.h
+++ b/SylixOS/arch/ppc/common/unaligned/porting.h
@@ -63,12 +63,6 @@ typedef __vector128 vector128;
#define flush_spe_to_thread(tcb)
-#define WARN_ON_ONCE(cond) \
-do { \
- if (cond) \
- _PrintFormat("%s(): %d warning!\r\n", __func__, __LINE__); \
-} while (0)
-
#define PPC_WARN_ALIGNMENT(a, b)
#define STACK_INT_FRAME_SIZE 0
diff --git a/SylixOS/arch/ppc/common/unaligned/ppcUnaligned.c b/SylixOS/arch/ppc/common/unaligned/ppcUnaligned.c
index 941aca5..4b96348 100644
--- a/SylixOS/arch/ppc/common/unaligned/ppcUnaligned.c
+++ b/SylixOS/arch/ppc/common/unaligned/ppcUnaligned.c
@@ -20,7 +20,6 @@
*********************************************************************************************************/
#define __SYLIXOS_KERNEL
#include "SylixOS.h"
-#include "arch/ppc/param/ppcParam.h"
#include <linux/compat.h>
#include "porting.h"
#include "sstep.h"
@@ -33,30 +32,25 @@ int fix_alignment(ARCH_REG_CTX *regs, enum instruction_type *inst_type);
** 函数名称: ppcUnalignedHandle
** 功能描述: PowerPC 非对齐处理
** 输 入 : pregctx 寄存器上下文
-** 输 出 : 终止信息
+** pabtInfo 终止信息
+** 输 出 : NONE
** 全局变量:
** 调用模块:
*********************************************************************************************************/
-LW_VMM_ABORT ppcUnalignedHandle (ARCH_REG_CTX *pregctx)
+VOID ppcUnalignedHandle (ARCH_REG_CTX *pregctx, PLW_VMM_ABORT pabtInfo)
{
- PPC_PARAM *param = archKernelParamGet();
INT iFixed;
enum instruction_type type;
- LW_VMM_ABORT abtInfo;
if (pregctx->REG_uiDar == pregctx->REG_uiPc) {
- goto sigbus;
- }
-
- if (param->PP_bUnalign == LW_FALSE) { /* Unsupport unalign access */
- goto sigbus;
+ goto sigbus;
}
iFixed = fix_alignment(pregctx, &type);
if (iFixed == 1) {
pregctx->REG_uiPc += 4; /* Skip over emulated inst */
- abtInfo.VMABT_uiType = 0;
- return (abtInfo);
+ pabtInfo->VMABT_uiType = LW_VMM_ABORT_TYPE_NOINFO;
+ return;
} else if (iFixed == -EFAULT) { /* Operand address was bad */
switch (type) {
@@ -67,7 +61,8 @@ LW_VMM_ABORT ppcUnalignedHandle (ARCH_REG_CTX *pregctx)
case STORE_VMX:
case STORE_VSX:
case STCX:
- abtInfo.VMABT_uiMethod = LW_VMM_ABORT_METHOD_WRITE;
+ pabtInfo->VMABT_uiType = LW_VMM_ABORT_TYPE_MAP;
+ pabtInfo->VMABT_uiMethod = LW_VMM_ABORT_METHOD_WRITE;
break;
case LOAD:
@@ -77,18 +72,16 @@ LW_VMM_ABORT ppcUnalignedHandle (ARCH_REG_CTX *pregctx)
case LOAD_VSX:
case LARX:
default:
- abtInfo.VMABT_uiMethod = LW_VMM_ABORT_METHOD_READ;
+ pabtInfo->VMABT_uiType = LW_VMM_ABORT_TYPE_MAP;
+ pabtInfo->VMABT_uiMethod = LW_VMM_ABORT_METHOD_READ;
break;
}
-
- abtInfo.VMABT_uiType = LW_VMM_ABORT_TYPE_MAP;
- return (abtInfo);
+ return;
}
sigbus:
- abtInfo.VMABT_uiMethod = BUS_ADRALN;
- abtInfo.VMABT_uiType = LW_VMM_ABORT_TYPE_BUS;
- return (abtInfo);
+ pabtInfo->VMABT_uiType = LW_VMM_ABORT_TYPE_BUS;
+ pabtInfo->VMABT_uiMethod = BUS_ADRALN;
}
/*********************************************************************************************************
END
diff --git a/SylixOS/arch/ppc/common/unaligned/ppcUnaligned.h b/SylixOS/arch/ppc/common/unaligned/ppcUnaligned.h
index 182a632..3097db5 100644
--- a/SylixOS/arch/ppc/common/unaligned/ppcUnaligned.h
+++ b/SylixOS/arch/ppc/common/unaligned/ppcUnaligned.h
@@ -22,7 +22,7 @@
#ifndef __ARCH_PPC_UNALIGNED_H
#define __ARCH_PPC_UNALIGNED_H
-LW_VMM_ABORT ppcUnalignedHandle(ARCH_REG_CTX *pregctx);
+VOID ppcUnalignedHandle(ARCH_REG_CTX *pregctx, PLW_VMM_ABORT pabtInfo);
#endif /* __ARCH_PPC_UNALIGNED_H */
/*********************************************************************************************************
diff --git a/SylixOS/arch/riscv/common/riscvExc.c b/SylixOS/arch/riscv/common/riscvExc.c
index 250eaf7..8aee8e3 100644
--- a/SylixOS/arch/riscv/common/riscvExc.c
+++ b/SylixOS/arch/riscv/common/riscvExc.c
@@ -21,6 +21,10 @@
#define __SYLIXOS_KERNEL
#include "SylixOS.h"
#include "dtrace.h"
+#if LW_CFG_RISCV_M_LEVEL > 0
+#include "arch/riscv/param/riscvParam.h"
+#include "arch/riscv/common/unaligned/riscvUnaligned.h"
+#endif /* LW_CFG_RISCV_M_LEVEL > 0 */
#if LW_CFG_VMM_EN > 0
#include "arch/riscv/mm/mmu/riscvMmu.h"
#endif /* LW_CFG_VMM_EN > 0 */
@@ -232,6 +236,40 @@ static VOID archLoadAccessTrapHandle (ARCH_REG_CTX *pregctx)
API_VmmAbortIsr(pregctx->REG_ulEpc, pregctx->REG_ulTrapVal, &abtInfo, ptcbCur);
}
/*********************************************************************************************************
+** 函数名称: archLoadUnalignedHandle
+** 功能描述: 非对齐内存加载异常处理
+** 输 入 : pabtctx abort 上下文
+** 输 出 : NONE
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+#if LW_CFG_RISCV_M_LEVEL > 0
+
+static VOID archLoadUnalignedHandle (PLW_VMM_ABORT_CTX pabtctx)
+{
+ riscvLoadUnalignedHandle(&pabtctx->ABTCTX_archRegCtx,
+ &pabtctx->ABTCTX_abtInfo);
+
+ API_VmmAbortReturn(pabtctx);
+}
+/*********************************************************************************************************
+** 函数名称: archStoreUnalignedHandle
+** 功能描述: 非对齐内存储存异常处理
+** 输 入 : pabtctx abort 上下文
+** 输 出 : NONE
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static VOID archStoreUnalignedHandle (PLW_VMM_ABORT_CTX pabtctx)
+{
+ riscvStoreUnalignedHandle(&pabtctx->ABTCTX_archRegCtx,
+ &pabtctx->ABTCTX_abtInfo);
+
+ API_VmmAbortReturn(pabtctx);
+}
+
+#endif /* LW_CFG_RISCV_M_LEVEL > 0 */
+/*********************************************************************************************************
** 函数名称: archLoadAddrMisalignTrapHandle
** 功能描述: Load address misaligned
** 输 入 : pregctx 寄存器上下文
@@ -245,12 +283,18 @@ static VOID archLoadAddrMisalignTrapHandle (ARCH_REG_CTX *pregctx)
{
PLW_CLASS_TCB ptcbCur;
LW_VMM_ABORT abtInfo;
+ RISCV_PARAM *param = archKernelParamGet();
LW_TCB_GET_CUR(ptcbCur);
abtInfo.VMABT_uiMethod = BUS_ADRALN;
abtInfo.VMABT_uiType = LW_VMM_ABORT_TYPE_BUS;
- if (abtInfo.VMABT_uiType) {
+
+ if (param->RISCV_bUnalign) {
+ API_VmmAbortIsrEx(pregctx->REG_ulEpc, pregctx->REG_ulTrapVal, &abtInfo, ptcbCur,
+ archLoadUnalignedHandle);
+
+ } else {
API_VmmAbortIsr(pregctx->REG_ulEpc, pregctx->REG_ulTrapVal, &abtInfo, ptcbCur);
}
}
@@ -268,12 +312,23 @@ static VOID archStoreAmoAddrMisalignTrapHandle (ARCH_REG_CTX *pregctx)
{
PLW_CLASS_TCB ptcbCur;
LW_VMM_ABORT abtInfo;
+#if LW_CFG_RISCV_M_LEVEL > 0
+ RISCV_PARAM *param = archKernelParamGet();
+#endif /* LW_CFG_RISCV_M_LEVEL > 0 */
LW_TCB_GET_CUR(ptcbCur);
abtInfo.VMABT_uiMethod = BUS_ADRALN;
abtInfo.VMABT_uiType = LW_VMM_ABORT_TYPE_BUS;
- if (abtInfo.VMABT_uiType) {
+
+#if LW_CFG_RISCV_M_LEVEL > 0
+ if (param->RISCV_bUnalign) {
+ API_VmmAbortIsrEx(pregctx->REG_ulEpc, pregctx->REG_ulTrapVal, &abtInfo, ptcbCur,
+ archStoreUnalignedHandle);
+
+ } else
+#endif /* LW_CFG_RISCV_M_LEVEL > 0 */
+ {
API_VmmAbortIsr(pregctx->REG_ulEpc, pregctx->REG_ulTrapVal, &abtInfo, ptcbCur);
}
}
@@ -483,6 +538,7 @@ VOID archTrapHandle (ARCH_REG_CTX *pregctx)
if (pfuncHandle) {
pfuncHandle(pregctx);
+
} else {
archDefaultTrapHandle(pregctx);
}
diff --git a/SylixOS/arch/riscv/common/unaligned/bits.h b/SylixOS/arch/riscv/common/unaligned/bits.h
new file mode 100644
index 0000000..cca1eac
--- /dev/null
+++ b/SylixOS/arch/riscv/common/unaligned/bits.h
@@ -0,0 +1,61 @@
+/*********************************************************************************************************
+**
+** 中国软件开源组织
+**
+** 嵌入式实时操作系统
+**
+** SylixOS(TM) LW : long wing
+**
+** Copyright All Rights Reserved
+**
+**--------------文件信息--------------------------------------------------------------------------------
+**
+** 文 件 名: bits.h
+**
+** 创 建 人: Jiao.JinXing (焦进星)
+**
+** 文件创建日期: 2018 年 08 月 29 日
+**
+** 描 述: RISC-V 体系构架位相关定义.
+*********************************************************************************************************/
+
+#ifndef __ARCH_RISCV_BITS_H
+#define __ARCH_RISCV_BITS_H
+
+#ifndef SYLIXOS
+#define likely(x) __builtin_expect((x), 1)
+#define unlikely(x) __builtin_expect((x), 0)
+#endif
+
+#define ROUNDUP(a, b) ((((a)-1)/(b)+1)*(b))
+#define ROUNDDOWN(a, b) ((a)/(b)*(b))
+
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#define CLAMP(a, lo, hi) MIN(MAX(a, lo), hi)
+
+#define EXTRACT_FIELD(val, which) (((val) & (which)) / ((which) & ~((which)-1)))
+#define INSERT_FIELD(val, which, fieldval) (((val) & ~(which)) | ((fieldval) * ((which) & ~((which)-1))))
+
+#define STR(x) XSTR(x)
+#define XSTR(x) #x
+
+#if __riscv_xlen == 64
+# define SLL32 sllw
+# define STORE sd
+# define LOAD ld
+# define LWU lwu
+# define LOG_REGBYTES 3
+#else
+# define SLL32 sll
+# define STORE sw
+# define LOAD lw
+# define LWU lw
+# define LOG_REGBYTES 2
+#endif
+#define REGBYTES (1 << LOG_REGBYTES)
+
+#endif /* __ARCH_RISCV_BITS_H */
+/*********************************************************************************************************
+ END
+*********************************************************************************************************/
diff --git a/SylixOS/arch/riscv/common/unaligned/config.h b/SylixOS/arch/riscv/common/unaligned/config.h
new file mode 100644
index 0000000..44246d5
--- /dev/null
+++ b/SylixOS/arch/riscv/common/unaligned/config.h
@@ -0,0 +1,32 @@
+/*********************************************************************************************************
+**
+** 中国软件开源组织
+**
+** 嵌入式实时操作系统
+**
+** SylixOS(TM) LW : long wing
+**
+** Copyright All Rights Reserved
+**
+**--------------文件信息--------------------------------------------------------------------------------
+**
+** 文 件 名: config.h
+**
+** 创 建 人: Jiao.JinXing (焦进星)
+**
+** 文件创建日期: 2018 年 08 月 29 日
+**
+** 描 述: RISC-V 体系构架非对齐处理配置.
+*********************************************************************************************************/
+
+#ifndef __ARCH_RISCV_UNALIGNED_CONFIG_H
+#define __ARCH_RISCV_UNALIGNED_CONFIG_H
+
+#if LW_CFG_CPU_FPU_EN > 0
+#define PK_ENABLE_FP_EMULATION
+#endif
+
+#endif /* __ARCH_RISCV_UNALIGNED_CONFIG_H */
+/*********************************************************************************************************
+ END
+*********************************************************************************************************/
diff --git a/SylixOS/arch/riscv/common/unaligned/emulation.h b/SylixOS/arch/riscv/common/unaligned/emulation.h
new file mode 100644
index 0000000..ca5d405
--- /dev/null
+++ b/SylixOS/arch/riscv/common/unaligned/emulation.h
@@ -0,0 +1,80 @@
+/*********************************************************************************************************
+**
+** 中国软件开源组织
+**
+** 嵌入式实时操作系统
+**
+** SylixOS(TM) LW : long wing
+**
+** Copyright All Rights Reserved
+**
+**--------------文件信息--------------------------------------------------------------------------------
+**
+** 文 件 名: emulation.h
+**
+** 创 建 人: Jiao.JinXing (焦进星)
+**
+** 文件创建日期: 2018 年 08 月 29 日
+**
+** 描 述: RISC-V 体系构架指令模拟相关定义.
+*********************************************************************************************************/
+
+#ifndef __ARCH_RISCV_EMULATION_H
+#define __ARCH_RISCV_EMULATION_H
+
+#ifndef SYLIXOS
+#include "encoding.h"
+#include "bits.h"
+#include <stdint.h>
+#endif
+
+typedef uintptr_t insn_t;
+
+#ifndef SYLIXOS
+typedef void (*emulation_func)(uintptr_t*, uintptr_t, uintptr_t, uintptr_t, insn_t);
+#define DECLARE_EMULATION_FUNC(name) void name(uintptr_t* regs, uintptr_t mcause, uintptr_t mepc, uintptr_t mstatus, insn_t insn)
+
+void misaligned_load_trap(uintptr_t* regs, uintptr_t mcause, uintptr_t mepc);
+void misaligned_store_trap(uintptr_t* regs, uintptr_t mcause, uintptr_t mepc);
+void redirect_trap(uintptr_t epc, uintptr_t mstatus, uintptr_t badaddr);
+DECLARE_EMULATION_FUNC(truly_illegal_insn);
+DECLARE_EMULATION_FUNC(emulate_rvc_0);
+DECLARE_EMULATION_FUNC(emulate_rvc_2);
+#endif
+
+#define SH_RD 7
+#define SH_RS1 15
+#define SH_RS2 20
+#define SH_RS2C 2
+
+#define RV_X(x, s, n) (((x) >> (s)) & ((1 << (n)) - 1))
+#define RVC_LW_IMM(x) ((RV_X(x, 6, 1) << 2) | (RV_X(x, 10, 3) << 3) | (RV_X(x, 5, 1) << 6))
+#define RVC_LD_IMM(x) ((RV_X(x, 10, 3) << 3) | (RV_X(x, 5, 2) << 6))
+#define RVC_LWSP_IMM(x) ((RV_X(x, 4, 3) << 2) | (RV_X(x, 12, 1) << 5) | (RV_X(x, 2, 2) << 6))
+#define RVC_LDSP_IMM(x) ((RV_X(x, 5, 2) << 3) | (RV_X(x, 12, 1) << 5) | (RV_X(x, 2, 3) << 6))
+#define RVC_SWSP_IMM(x) ((RV_X(x, 9, 4) << 2) | (RV_X(x, 7, 2) << 6))
+#define RVC_SDSP_IMM(x) ((RV_X(x, 10, 3) << 3) | (RV_X(x, 7, 3) << 6))
+#define RVC_RS1S(insn) (8 + RV_X(insn, SH_RD, 3))
+#define RVC_RS2S(insn) (8 + RV_X(insn, SH_RS2C, 3))
+#define RVC_RS2(insn) RV_X(insn, SH_RS2C, 5)
+
+#define SHIFT_RIGHT(x, y) ((y) < 0 ? ((x) << -(y)) : ((x) >> (y)))
+#define GET_REG(insn, pos, regs) ({ \
+ int mask = (1 << (5+LOG_REGBYTES)) - (1 << LOG_REGBYTES); \
+ (uintptr_t*)((uintptr_t)regs + (SHIFT_RIGHT(insn, (pos) - LOG_REGBYTES) & (mask))); \
+})
+#define GET_RS1(insn, regs) (*GET_REG(insn, SH_RS1, regs))
+#define GET_RS2(insn, regs) (*GET_REG(insn, SH_RS2, regs))
+#define GET_RS1S(insn, regs) (*GET_REG(RVC_RS1S(insn), 0, regs))
+#define GET_RS2S(insn, regs) (*GET_REG(RVC_RS2S(insn), 0, regs))
+#define GET_RS2C(insn, regs) (*GET_REG(insn, SH_RS2C, regs))
+#define GET_SP(regs) (*GET_REG(2, 0, regs))
+#define SET_RD(insn, regs, val) (*GET_REG(insn, SH_RD, regs) = (val))
+#define IMM_I(insn) ((int32_t)(insn) >> 20)
+#define IMM_S(insn) (((int32_t)(insn) >> 25 << 5) | (int32_t)(((insn) >> 7) & 0x1f))
+#define MASK_FUNCT3 0x7000
+
+#endif /* __ARCH_RISCV_EMULATION_H */
+/*********************************************************************************************************
+ END
+*********************************************************************************************************/
diff --git a/SylixOS/arch/riscv/common/unaligned/fp_asm.S b/SylixOS/arch/riscv/common/unaligned/fp_asm.S
new file mode 100644
index 0000000..138cb84
--- /dev/null
+++ b/SylixOS/arch/riscv/common/unaligned/fp_asm.S
@@ -0,0 +1,235 @@
+;/*********************************************************************************************************
+;**
+;** 中国软件开源组织
+;**
+;** 嵌入式实时操作系统
+;**
+;** SylixOS(TM)
+;**
+;** Copyright All Rights Reserved
+;**
+;**--------------文件信息--------------------------------------------------------------------------------
+;**
+;** 文 件 名: fp_asm.S
+;**
+;** 创 建 人: Jiao.JinXing (焦进星)
+;**
+;** 文件创建日期: 2018 年 08 月 29 日
+;**
+;** 描 述: RISC-V 体系架构 FPU 支持.
+;*********************************************************************************************************/
+
+#ifndef ASSEMBLY
+#define ASSEMBLY 1
+#endif
+
+#include <arch/assembler.h>
+
+#if LW_CFG_RISCV_M_LEVEL > 0
+#if LW_CFG_CPU_FPU_EN > 0
+
+;/*********************************************************************************************************
+; A0 寄存器的指令编码
+;*********************************************************************************************************/
+
+#define RISCV_A0 10
+
+;/*********************************************************************************************************
+; FLD FSD 指令
+;*********************************************************************************************************/
+
+#define RISCV_FLD(rd, offset, rs1) \
+ .word ((offset << 20) | (rs1 << 15) | (0x3 << 12) | (rd << 7) | 0x7)
+
+#define RISCV_FSD(rs2, offset, rs1) \
+ .word (((offset >> 5) << 25) | (rs2 << 20) | (rs1 << 15) | (0x3 << 12) | ((offset & 0x1f) << 7) | 0x27)
+
+;/*********************************************************************************************************
+; FMV.X.S FMV.S.X 指令
+;*********************************************************************************************************/
+
+#define RISCV_FMV_X_S_A0(which) \
+ .word (0xe0000553 + (((which) * 8) << 12))
+
+#define RISCV_FMV_S_X_A0(which) \
+ .word (0xf0050053 + (((which) * 8) << 4))
+
+;/*********************************************************************************************************
+; FMV.X.D FMV.S.D 指令
+;*********************************************************************************************************/
+
+#define RISCV_FMV_X_D_A0(which) \
+ .word (0xe2000553 + (((which) * 8) << 12))
+
+#define RISCV_FMV_D_X_A0(which) \
+ .word (0xf2050053 + (((which) * 8) << 4))
+
+;/*********************************************************************************************************
+; get_f32 put_f32
+;*********************************************************************************************************/
+
+#define get_f32(which) .align 1; RISCV_FMV_X_S_A0(which); jr t0
+#define put_f32(which) .align 1; RISCV_FMV_S_X_A0(which); jr t0
+
+;/*********************************************************************************************************
+; get_f64 put_f64
+;*********************************************************************************************************/
+
+#if __riscv_xlen == 64
+# define get_f64(which) .align 1; RISCV_FMV_X_D_A0(which); jr t0
+# define put_f64(which) .align 1; RISCV_FMV_D_X_A0(which); jr t0
+#else
+# define get_f64(which) .align 1; RISCV_FSD(which, 0, RISCV_A0); jr t0
+# define put_f64(which) .align 1; RISCV_FLD(which, 0, RISCV_A0); jr t0
+#endif
+
+ .text
+ .option norvc
+ .globl get_f32_reg
+ get_f32_reg:
+ get_f32(0)
+ get_f32(1)
+ get_f32(2)
+ get_f32(3)
+ get_f32(4)
+ get_f32(5)
+ get_f32(6)
+ get_f32(7)
+ get_f32(8)
+ get_f32(9)
+ get_f32(10)
+ get_f32(11)
+ get_f32(12)
+ get_f32(13)
+ get_f32(14)
+ get_f32(15)
+ get_f32(16)
+ get_f32(17)
+ get_f32(18)
+ get_f32(19)
+ get_f32(20)
+ get_f32(21)
+ get_f32(22)
+ get_f32(23)
+ get_f32(24)
+ get_f32(25)
+ get_f32(26)
+ get_f32(27)
+ get_f32(28)
+ get_f32(29)
+ get_f32(30)
+ get_f32(31)
+
+ .text
+ .globl put_f32_reg
+ put_f32_reg:
+ put_f32(0)
+ put_f32(1)
+ put_f32(2)
+ put_f32(3)
+ put_f32(4)
+ put_f32(5)
+ put_f32(6)
+ put_f32(7)
+ put_f32(8)
+ put_f32(9)
+ put_f32(10)
+ put_f32(11)
+ put_f32(12)
+ put_f32(13)
+ put_f32(14)
+ put_f32(15)
+ put_f32(16)
+ put_f32(17)
+ put_f32(18)
+ put_f32(19)
+ put_f32(20)
+ put_f32(21)
+ put_f32(22)
+ put_f32(23)
+ put_f32(24)
+ put_f32(25)
+ put_f32(26)
+ put_f32(27)
+ put_f32(28)
+ put_f32(29)
+ put_f32(30)
+ put_f32(31)
+
+ .text
+ .globl get_f64_reg
+ get_f64_reg:
+ get_f64(0)
+ get_f64(1)
+ get_f64(2)
+ get_f64(3)
+ get_f64(4)
+ get_f64(5)
+ get_f64(6)
+ get_f64(7)
+ get_f64(8)
+ get_f64(9)
+ get_f64(10)
+ get_f64(11)
+ get_f64(12)
+ get_f64(13)
+ get_f64(14)
+ get_f64(15)
+ get_f64(16)
+ get_f64(17)
+ get_f64(18)
+ get_f64(19)
+ get_f64(20)
+ get_f64(21)
+ get_f64(22)
+ get_f64(23)
+ get_f64(24)
+ get_f64(25)
+ get_f64(26)
+ get_f64(27)
+ get_f64(28)
+ get_f64(29)
+ get_f64(30)
+ get_f64(31)
+
+ .text
+ .globl put_f64_reg
+ put_f64_reg:
+ put_f64(0)
+ put_f64(1)
+ put_f64(2)
+ put_f64(3)
+ put_f64(4)
+ put_f64(5)
+ put_f64(6)
+ put_f64(7)
+ put_f64(8)
+ put_f64(9)
+ put_f64(10)
+ put_f64(11)
+ put_f64(12)
+ put_f64(13)
+ put_f64(14)
+ put_f64(15)
+ put_f64(16)
+ put_f64(17)
+ put_f64(18)
+ put_f64(19)
+ put_f64(20)
+ put_f64(21)
+ put_f64(22)
+ put_f64(23)
+ put_f64(24)
+ put_f64(25)
+ put_f64(26)
+ put_f64(27)
+ put_f64(28)
+ put_f64(29)
+ put_f64(30)
+ put_f64(31)
+
+#endif
+#endif
+;/*********************************************************************************************************
+; END
+;*********************************************************************************************************/
diff --git a/SylixOS/arch/riscv/common/unaligned/fp_emulation.h b/SylixOS/arch/riscv/common/unaligned/fp_emulation.h
new file mode 100644
index 0000000..539714d
--- /dev/null
+++ b/SylixOS/arch/riscv/common/unaligned/fp_emulation.h
@@ -0,0 +1,76 @@
+/*********************************************************************************************************
+**
+** 中国软件开源组织
+**
+** 嵌入式实时操作系统
+**
+** SylixOS(TM) LW : long wing
+**
+** Copyright All Rights Reserved
+**
+**--------------文件信息--------------------------------------------------------------------------------
+**
+** 文 件 名: fp_emulation.h
+**
+** 创 建 人: Jiao.JinXing (焦进星)
+**
+** 文件创建日期: 2018 年 08 月 29 日
+**
+** 描 述: RISC-V 体系构架 FPU 模拟相关定义.
+*********************************************************************************************************/
+
+#ifndef __ARCH_RISCV_FP_EMU_H
+#define __ARCH_RISCV_FP_EMU_H
+
+#include "emulation.h"
+
+#define GET_PRECISION(insn) (((insn) >> 25) & 3)
+#define GET_RM(insn) (((insn) >> 12) & 7)
+#define PRECISION_S 0
+#define PRECISION_D 1
+
+#define GET_F32_REG(insn, pos, regs) ({ \
+ register int32_t value asm("a0") = SHIFT_RIGHT(insn, (pos)-3) & 0xf8; \
+ uintptr_t tmp; \
+ asm ("1: auipc %0, %%pcrel_hi(get_f32_reg); add %0, %0, %1; jalr t0, %0, %%pcrel_lo(1b)" : "=&r"(tmp), "+&r"(value) :: "t0"); \
+ value; })
+
+#define SET_F32_REG(insn, pos, regs, val) ({ \
+ register uint32_t value asm("a0") = (val); \
+ uintptr_t offset = SHIFT_RIGHT(insn, (pos)-3) & 0xf8; \
+ uintptr_t tmp; \
+ asm volatile ("1: auipc %0, %%pcrel_hi(put_f32_reg); add %0, %0, %2; jalr t0, %0, %%pcrel_lo(1b)" : "=&r"(tmp) : "r"(value), "r"(offset) : "t0"); })
+
+#define GET_F64_REG(insn, pos, regs) ({ \
+ register uintptr_t value asm("a0") = SHIFT_RIGHT(insn, (pos)-3) & 0xf8; \
+ uintptr_t tmp; \
+ asm ("1: auipc %0, %%pcrel_hi(get_f64_reg); add %0, %0, %1; jalr t0, %0, %%pcrel_lo(1b)" : "=&r"(tmp), "+&r"(value) :: "t0"); \
+ sizeof(uintptr_t) == 4 ? *(int64_t*)value : (int64_t)value; })
+
+#define SET_F64_REG(insn, pos, regs, val) ({ \
+ uint64_t __val = (val); \
+ register uintptr_t value asm("a0") = sizeof(uintptr_t) == 4 ? (uintptr_t)&__val : (uintptr_t)__val; \
+ uintptr_t offset = SHIFT_RIGHT(insn, (pos)-3) & 0xf8; \
+ uintptr_t tmp; \
+ asm volatile ("1: auipc %0, %%pcrel_hi(put_f64_reg); add %0, %0, %2; jalr t0, %0, %%pcrel_lo(1b)" : "=&r"(tmp) : "r"(value), "r"(offset) : "t0"); })
+
+#define SET_FS_DIRTY() ((void) 0)
+
+#define GET_F32_RS1(insn, regs) (GET_F32_REG(insn, 15, regs))
+#define GET_F32_RS2(insn, regs) (GET_F32_REG(insn, 20, regs))
+#define GET_F32_RS3(insn, regs) (GET_F32_REG(insn, 27, regs))
+#define GET_F64_RS1(insn, regs) (GET_F64_REG(insn, 15, regs))
+#define GET_F64_RS2(insn, regs) (GET_F64_REG(insn, 20, regs))
+#define GET_F64_RS3(insn, regs) (GET_F64_REG(insn, 27, regs))
+#define SET_F32_RD(insn, regs, val) (SET_F32_REG(insn, 7, regs, val), SET_FS_DIRTY())
+#define SET_F64_RD(insn, regs, val) (SET_F64_REG(insn, 7, regs, val), SET_FS_DIRTY())
+
+#define GET_F32_RS2C(insn, regs) (GET_F32_REG(insn, 2, regs))
+#define GET_F32_RS2S(insn, regs) (GET_F32_REG(RVC_RS2S(insn), 0, regs))
+#define GET_F64_RS2C(insn, regs) (GET_F64_REG(insn, 2, regs))
+#define GET_F64_RS2S(insn, regs) (GET_F64_REG(RVC_RS2S(insn), 0, regs))
+
+#endif /* __ARCH_RISCV_FP_EMU_H */
+/*********************************************************************************************************
+ END
+*********************************************************************************************************/
diff --git a/SylixOS/arch/riscv/common/unaligned/misaligned_ldst.c b/SylixOS/arch/riscv/common/unaligned/misaligned_ldst.c
new file mode 100644
index 0000000..3aa90c8
--- /dev/null
+++ b/SylixOS/arch/riscv/common/unaligned/misaligned_ldst.c
@@ -0,0 +1,184 @@
+/*********************************************************************************************************
+**
+** 中国软件开源组织
+**
+** 嵌入式实时操作系统
+**
+** SylixOS(TM) LW : long wing
+**
+** Copyright All Rights Reserved
+**
+**--------------文件信息--------------------------------------------------------------------------------
+**
+** 文 件 名: misaligned_ldst.c
+**
+** 创 建 人: Jiao.JinXing (焦进星)
+**
+** 文件创建日期: 2018 年 08 月 29 日
+**
+** 描 述: RISC-V 体系构架非对齐处理.
+*********************************************************************************************************/
+#ifdef SYLIXOS
+#define __SYLIXOS_KERNEL
+#include "SylixOS.h"
+#include "config.h"
+#include "bits.h"
+#endif
+
+#include "emulation.h"
+#include "fp_emulation.h"
+#include "unprivileged_memory.h"
+#ifndef SYLIXOS
+#include "mtrap.h"
+#include "config.h"
+#include "pk.h"
+#endif
+
+#if LW_CFG_RISCV_M_LEVEL > 0
+
+union byte_array {
+ uint8_t bytes[8];
+ uintptr_t intx;
+ uint64_t int64;
+};
+
+static inline int insn_len(long insn)
+{
+ return (insn & 0x3) < 0x3 ? 2 : 4;
+}
+
+int misaligned_load_trap(ARCH_REG_CTX *pregctx)
+{
+ union byte_array val;
+ uintptr_t mstatus;
+ insn_t insn = get_insn(pregctx->REG_ulEpc, &mstatus);
+ uintptr_t npc = pregctx->REG_ulEpc + insn_len(insn);
+ uintptr_t addr = pregctx->REG_ulTrapVal;
+ uintptr_t *regs = (uintptr_t *)pregctx->REG_ulReg;
+
+ int shift = 0, fp = 0, len;
+ if ((insn & MASK_LW) == MATCH_LW)
+ len = 4, shift = 8*(sizeof(uintptr_t) - len);
+#if __riscv_xlen == 64
+ else if ((insn & MASK_LD) == MATCH_LD)
+ len = 8, shift = 8*(sizeof(uintptr_t) - len);
+ else if ((insn & MASK_LWU) == MATCH_LWU)
+ len = 4;
+#endif
+#ifdef PK_ENABLE_FP_EMULATION
+ else if ((insn & MASK_FLD) == MATCH_FLD)
+ fp = 1, len = 8;
+ else if ((insn & MASK_FLW) == MATCH_FLW)
+ fp = 1, len = 4;
+#endif
+ else if ((insn & MASK_LH) == MATCH_LH)
+ len = 2, shift = 8*(sizeof(uintptr_t) - len);
+ else if ((insn & MASK_LHU) == MATCH_LHU)
+ len = 2;
+#ifdef __riscv_compressed
+# if __riscv_xlen >= 64
+ else if ((insn & MASK_C_LD) == MATCH_C_LD)
+ len = 8, shift = 8*(sizeof(uintptr_t) - len), insn = RVC_RS2S(insn) << SH_RD;
+ else if ((insn & MASK_C_LDSP) == MATCH_C_LDSP && ((insn >> SH_RD) & 0x1f))
+ len = 8, shift = 8*(sizeof(uintptr_t) - len);
+# endif
+ else if ((insn & MASK_C_LW) == MATCH_C_LW)
+ len = 4, shift = 8*(sizeof(uintptr_t) - len), insn = RVC_RS2S(insn) << SH_RD;
+ else if ((insn & MASK_C_LWSP) == MATCH_C_LWSP && ((insn >> SH_RD) & 0x1f))
+ len = 4, shift = 8*(sizeof(uintptr_t) - len);
+# ifdef PK_ENABLE_FP_EMULATION
+ else if ((insn & MASK_C_FLD) == MATCH_C_FLD)
+ fp = 1, len = 8, insn = RVC_RS2S(insn) << SH_RD;
+ else if ((insn & MASK_C_FLDSP) == MATCH_C_FLDSP)
+ fp = 1, len = 8;
+# if __riscv_xlen == 32
+ else if ((insn & MASK_C_FLW) == MATCH_C_FLW)
+ fp = 1, len = 4, insn = RVC_RS2S(insn) << SH_RD;
+ else if ((insn & MASK_C_FLWSP) == MATCH_C_FLWSP)
+ fp = 1, len = 4;
+# endif
+# endif
+#endif
+ else
+ return (PX_ERROR);
+
+ val.int64 = 0;
+ for (intptr_t i = 0; i < len; i++)
+ val.bytes[i] = load_uint8_t((void *)(addr + i), pregctx->REG_ulEpc);
+
+ if (!fp)
+ SET_RD(insn, regs, (intptr_t)val.intx << shift >> shift);
+ else if (len == 8)
+ SET_F64_RD(insn, regs, val.int64);
+ else
+ SET_F32_RD(insn, regs, val.intx);
+
+ pregctx->REG_ulEpc = npc;
+
+ return (ERROR_NONE);
+}
+
+int misaligned_store_trap(ARCH_REG_CTX *pregctx)
+{
+ union byte_array val;
+ uintptr_t mstatus;
+ insn_t insn = get_insn(pregctx->REG_ulEpc, &mstatus);
+ uintptr_t npc = pregctx->REG_ulEpc + insn_len(insn);
+ int len;
+ uintptr_t *regs = (uintptr_t *)pregctx->REG_ulReg;
+
+ val.intx = GET_RS2(insn, regs);
+ if ((insn & MASK_SW) == MATCH_SW)
+ len = 4;
+#if __riscv_xlen == 64
+ else if ((insn & MASK_SD) == MATCH_SD)
+ len = 8;
+#endif
+#ifdef PK_ENABLE_FP_EMULATION
+ else if ((insn & MASK_FSD) == MATCH_FSD)
+ len = 8, val.int64 = GET_F64_RS2(insn, regs);
+ else if ((insn & MASK_FSW) == MATCH_FSW)
+ len = 4, val.intx = GET_F32_RS2(insn, regs);
+#endif
+ else if ((insn & MASK_SH) == MATCH_SH)
+ len = 2;
+#ifdef __riscv_compressed
+# if __riscv_xlen >= 64
+ else if ((insn & MASK_C_SD) == MATCH_C_SD)
+ len = 8, val.intx = GET_RS2S(insn, regs);
+ else if ((insn & MASK_C_SDSP) == MATCH_C_SDSP && ((insn >> SH_RD) & 0x1f))
+ len = 8, val.intx = GET_RS2C(insn, regs);
+# endif
+ else if ((insn & MASK_C_SW) == MATCH_C_SW)
+ len = 4, val.intx = GET_RS2S(insn, regs);
+ else if ((insn & MASK_C_SWSP) == MATCH_C_SWSP && ((insn >> SH_RD) & 0x1f))
+ len = 4, val.intx = GET_RS2C(insn, regs);
+# ifdef PK_ENABLE_FP_EMULATION
+ else if ((insn & MASK_C_FSD) == MATCH_C_FSD)
+ len = 8, val.int64 = GET_F64_RS2S(insn, regs);
+ else if ((insn & MASK_C_FSDSP) == MATCH_C_FSDSP)
+ len = 8, val.int64 = GET_F64_RS2C(insn, regs);
+# if __riscv_xlen == 32
+ else if ((insn & MASK_C_FSW) == MATCH_C_FSW)
+ len = 4, val.intx = GET_F32_RS2S(insn, regs);
+ else if ((insn & MASK_C_FSWSP) == MATCH_C_FSWSP)
+ len = 4, val.intx = GET_F32_RS2C(insn, regs);
+# endif
+# endif
+#endif
+ else
+ return (PX_ERROR);
+
+ uintptr_t addr = pregctx->REG_ulTrapVal;
+ for (int i = 0; i < len; i++)
+ store_uint8_t((void *)(addr + i), val.bytes[i], pregctx->REG_ulEpc);
+
+ pregctx->REG_ulEpc = npc;
+
+ return (ERROR_NONE);
+}
+
+#endif /* LW_CFG_RISCV_M_LEVEL > 0 */
+/*********************************************************************************************************
+ END
+*********************************************************************************************************/
diff --git a/SylixOS/arch/riscv/common/unaligned/riscvUnaligned.c b/SylixOS/arch/riscv/common/unaligned/riscvUnaligned.c
new file mode 100644
index 0000000..70c107d
--- /dev/null
+++ b/SylixOS/arch/riscv/common/unaligned/riscvUnaligned.c
@@ -0,0 +1,71 @@
+/*********************************************************************************************************
+**
+** 中国软件开源组织
+**
+** 嵌入式实时操作系统
+**
+** SylixOS(TM) LW : long wing
+**
+** Copyright All Rights Reserved
+**
+**--------------文件信息--------------------------------------------------------------------------------
+**
+** 文 件 名: riscvUnaligned.c
+**
+** 创 建 人: Jiao.JinXing (焦进星)
+**
+** 文件创建日期: 2018 年 08 月 27 日
+**
+** 描 述: RISC-V 体系构架非对齐处理.
+*********************************************************************************************************/
+#define __SYLIXOS_KERNEL
+#include "SylixOS.h"
+#if LW_CFG_RISCV_M_LEVEL > 0
+/*********************************************************************************************************
+ 函数声明
+*********************************************************************************************************/
+extern int misaligned_load_trap(ARCH_REG_CTX *pregctx);
+extern int misaligned_store_trap(ARCH_REG_CTX *pregctx);
+/*********************************************************************************************************
+** 函数名称: riscvLoadUnalignedHandle
+** 功能描述: RISC-V load 指令非对齐处理
+** 输 入 : pregctx 寄存器上下文
+** pabtInfo 异常信息
+** 输 出 : 终止信息
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+VOID riscvLoadUnalignedHandle (ARCH_REG_CTX *pregctx, LW_VMM_ABORT *pabtInfo)
+{
+ if (misaligned_load_trap(pregctx) == ERROR_NONE) {
+ pabtInfo->VMABT_uiType = LW_VMM_ABORT_TYPE_NOINFO;
+
+ } else {
+ pabtInfo->VMABT_uiMethod = BUS_ADRALN;
+ pabtInfo->VMABT_uiType = LW_VMM_ABORT_TYPE_BUS;
+ }
+}
+/*********************************************************************************************************
+** 函数名称: riscvStoreUnalignedHandle
+** 功能描述: RISC-V store 指令非对齐处理
+** 输 入 : pregctx 寄存器上下文
+** pabtInfo 异常信息
+** 输 出 : 终止信息
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+VOID riscvStoreUnalignedHandle (ARCH_REG_CTX *pregctx, LW_VMM_ABORT *pabtInfo)
+{
+ if (misaligned_store_trap(pregctx) == ERROR_NONE) {
+ pabtInfo->VMABT_uiType = LW_VMM_ABORT_TYPE_NOINFO;
+
+ } else {
+ pabtInfo->VMABT_uiMethod = BUS_ADRALN;
+ pabtInfo->VMABT_uiType = LW_VMM_ABORT_TYPE_BUS;
+ }
+}
+
+#endif /* LW_CFG_RISCV_M_LEVEL > 0 */
+/*********************************************************************************************************
+ END
+*********************************************************************************************************/
diff --git a/SylixOS/arch/riscv/common/unaligned/riscvUnaligned.h b/SylixOS/arch/riscv/common/unaligned/riscvUnaligned.h
new file mode 100644
index 0000000..65a0999
--- /dev/null
+++ b/SylixOS/arch/riscv/common/unaligned/riscvUnaligned.h
@@ -0,0 +1,35 @@
+/*********************************************************************************************************
+**
+** 中国软件开源组织
+**
+** 嵌入式实时操作系统
+**
+** SylixOS(TM) LW : long wing
+**
+** Copyright All Rights Reserved
+**
+**--------------文件信息--------------------------------------------------------------------------------
+**
+** 文 件 名: riscvUnaligned.h
+**
+** 创 建 人: Jiao.JinXing (焦进星)
+**
+** 文件创建日期: 2018 年 11 月 16 日
+**
+** 描 述: RISC-V 体系构架非对齐处理.
+*********************************************************************************************************/
+
+#ifndef __ARCH_RISCVUNALIGNED_H
+#define __ARCH_RISCVUNALIGNED_H
+
+#if LW_CFG_RISCV_M_LEVEL > 0
+
+extern VOID riscvLoadUnalignedHandle(ARCH_REG_CTX *pregctx, LW_VMM_ABORT *pabtInfo);
+extern VOID riscvStoreUnalignedHandle(ARCH_REG_CTX *pregctx, LW_VMM_ABORT *pabtInfo);
+
+#endif /* LW_CFG_RISCV_M_LEVEL > 0 */
+
+#endif /* __ARCH_RISCVUNALIGNED_H */
+/*********************************************************************************************************
+ END
+*********************************************************************************************************/
diff --git a/SylixOS/arch/riscv/common/unaligned/unprivileged_memory.h b/SylixOS/arch/riscv/common/unaligned/unprivileged_memory.h
new file mode 100644
index 0000000..928b7f6
--- /dev/null
+++ b/SylixOS/arch/riscv/common/unaligned/unprivileged_memory.h
@@ -0,0 +1,129 @@
+/*********************************************************************************************************
+**
+** 中国软件开源组织
+**
+** 嵌入式实时操作系统
+**
+** SylixOS(TM) LW : long wing
+**
+** Copyright All Rights Reserved
+**
+**--------------文件信息--------------------------------------------------------------------------------
+**
+** 文 件 名: unprivileged_memory.h
+**
+** 创 建 人: Jiao.JinXing (焦进星)
+**
+** 文件创建日期: 2018 年 08 月 29 日
+**
+** 描 述: RISC-V 体系构架非特权内存访问.
+*********************************************************************************************************/
+
+#ifndef __ARCH_RISCV_UNPRIV_MEM_H
+#define __ARCH_RISCV_UNPRIV_MEM_H
+
+#ifndef SYLIXOS
+#include "encoding.h"
+#include "bits.h"
+#include <stdint.h>
+#endif
+
+#define DECLARE_UNPRIVILEGED_LOAD_FUNCTION(type, insn) \
+ static inline type load_##type(const type* addr, uintptr_t mepc) \
+ { \
+ register uintptr_t __mepc asm ("a2") = mepc; \
+ register uintptr_t __mstatus asm ("a3"); \
+ type val; \
+ asm ("csrrs %0, mstatus, %3\n" \
+ #insn " %1, %2\n" \
+ "csrw mstatus, %0" \
+ : "+&r" (__mstatus), "=&r" (val) \
+ : "m" (*addr), "r" (MSTATUS_MPRV), "r" (__mepc)); \
+ return val; \
+ }
+
+#define DECLARE_UNPRIVILEGED_STORE_FUNCTION(type, insn) \
+ static inline void store_##type(type* addr, type val, uintptr_t mepc) \
+ { \
+ register uintptr_t __mepc asm ("a2") = mepc; \
+ register uintptr_t __mstatus asm ("a3"); \
+ asm volatile ("csrrs %0, mstatus, %3\n" \
+ #insn " %1, %2\n" \
+ "csrw mstatus, %0" \
+ : "+&r" (__mstatus) \
+ : "r" (val), "m" (*addr), "r" (MSTATUS_MPRV), \
+ "r" (__mepc)); \
+ }
+
+DECLARE_UNPRIVILEGED_LOAD_FUNCTION(uint8_t, lbu)
+DECLARE_UNPRIVILEGED_LOAD_FUNCTION(uint16_t, lhu)
+DECLARE_UNPRIVILEGED_LOAD_FUNCTION(int8_t, lb)
+DECLARE_UNPRIVILEGED_LOAD_FUNCTION(int16_t, lh)
+DECLARE_UNPRIVILEGED_LOAD_FUNCTION(int32_t, lw)
+DECLARE_UNPRIVILEGED_STORE_FUNCTION(uint8_t, sb)
+DECLARE_UNPRIVILEGED_STORE_FUNCTION(uint16_t, sh)
+DECLARE_UNPRIVILEGED_STORE_FUNCTION(uint32_t, sw)
+#if __riscv_xlen == 64
+DECLARE_UNPRIVILEGED_LOAD_FUNCTION(uint32_t, lwu)
+DECLARE_UNPRIVILEGED_LOAD_FUNCTION(uint64_t, ld)
+DECLARE_UNPRIVILEGED_STORE_FUNCTION(uint64_t, sd)
+DECLARE_UNPRIVILEGED_LOAD_FUNCTION(uintptr_t, ld)
+#else
+DECLARE_UNPRIVILEGED_LOAD_FUNCTION(uint32_t, lw)
+DECLARE_UNPRIVILEGED_LOAD_FUNCTION(uintptr_t, lw)
+
+static inline uint64_t load_uint64_t(const uint64_t* addr, uintptr_t mepc)
+{
+ return load_uint32_t((uint32_t*)addr, mepc)
+ + ((uint64_t)load_uint32_t((uint32_t*)addr + 1, mepc) << 32);
+}
+
+static inline void store_uint64_t(uint64_t* addr, uint64_t val, uintptr_t mepc)
+{
+ store_uint32_t((uint32_t*)addr, val, mepc);
+ store_uint32_t((uint32_t*)addr + 1, val >> 32, mepc);
+}
+#endif
+
+static inline uintptr_t get_insn(uintptr_t mepc, uintptr_t* mstatus)
+{
+ register uintptr_t __mepc asm ("a2") = mepc;
+ register uintptr_t __mstatus asm ("a3");
+ uintptr_t val;
+#ifndef __riscv_compressed
+ asm ("csrrs %[mstatus], mstatus, %[mprv]\n"
+ STR(LWU) " %[insn], (%[addr])\n"
+ "csrw mstatus, %[mstatus]"
+ : [mstatus] "+&r" (__mstatus), [insn] "=&r" (val)
+ : [mprv] "r" (MSTATUS_MPRV | MSTATUS_MXR), [addr] "r" (__mepc));
+#else
+ uintptr_t rvc_mask = 3, tmp;
+ asm ("csrrs %[mstatus], mstatus, %[mprv]\n"
+ "and %[tmp], %[addr], 2\n"
+ "bnez %[tmp], 1f\n"
+ STR(LWU) " %[insn], (%[addr])\n"
+ "and %[tmp], %[insn], %[rvc_mask]\n"
+ "beq %[tmp], %[rvc_mask], 2f\n"
+ "sll %[insn], %[insn], %[xlen_minus_16]\n"
+ "srl %[insn], %[insn], %[xlen_minus_16]\n"
+ "j 2f\n"
+ "1:\n"
+ "lhu %[insn], (%[addr])\n"
+ "and %[tmp], %[insn], %[rvc_mask]\n"
+ "bne %[tmp], %[rvc_mask], 2f\n"
+ "lhu %[tmp], 2(%[addr])\n"
+ "sll %[tmp], %[tmp], 16\n"
+ "add %[insn], %[insn], %[tmp]\n"
+ "2: csrw mstatus, %[mstatus]"
+ : [mstatus] "+&r" (__mstatus), [insn] "=&r" (val), [tmp] "=&r" (tmp)
+ : [mprv] "r" (MSTATUS_MPRV | MSTATUS_MXR), [addr] "r" (__mepc),
+ [rvc_mask] "r" (rvc_mask), [xlen_minus_16] "i" (__riscv_xlen - 16));
+#endif
+ *mstatus = __mstatus;
+ return val;
+}
+
+#endif /* __ARCH_RISCV_UNPRIV_MEM_H */
+/*********************************************************************************************************
+ END
+*********************************************************************************************************/
diff --git a/SylixOS/arch/sparc/backtrace/sparcBacktrace.c b/SylixOS/arch/sparc/backtrace/sparcBacktrace.c
index ce93e25..4e23f08 100644
--- a/SylixOS/arch/sparc/backtrace/sparcBacktrace.c
+++ b/SylixOS/arch/sparc/backtrace/sparcBacktrace.c
@@ -57,11 +57,15 @@ int backtrace (void **array, int size)
}
SPARC_FLUSH_REG_WINDOWS();
- for (count = 1; count < size; count++) {
- array[count] = current->return_address;
+ for (count = 1; count < size;) {
+ if (current->return_address) {
+ array[count++] = current->return_address;
+ }
+
if (!current->next) {
break;
}
+
current = (struct layout *)(current->next + BACKTRACE_STACK_BIAS);
}
diff --git a/SylixOS/arch/sparc/common/sparcExc.c b/SylixOS/arch/sparc/common/sparcExc.c
index e26b24c..5a0608b 100644
--- a/SylixOS/arch/sparc/common/sparcExc.c
+++ b/SylixOS/arch/sparc/common/sparcExc.c
@@ -24,16 +24,13 @@
#if LW_CFG_VMM_EN > 0
#include "arch/sparc/mm/mmu/sparcMmu.h"
#endif /* LW_CFG_VMM_EN > 0 */
+#include "arch/sparc/common/unaligned/sparcUnaligned.h"
/*********************************************************************************************************
外部引用变量声明
*********************************************************************************************************/
extern LW_CLASS_CPU _K_cpuTable[]; /* CPU 表 */
extern LW_STACK _K_stkInterruptStack[LW_CFG_MAX_PROCESSORS][LW_CFG_INT_STK_SIZE / sizeof(LW_STACK)];
/*********************************************************************************************************
- 外部函数声明
-*********************************************************************************************************/
-extern UINT sparcUnalignedHandle(ARCH_REG_CTX *regs, addr_t *pulAbortAddr, UINT *puiMethod);
-/*********************************************************************************************************
中断相关
*********************************************************************************************************/
#if LW_CFG_SMP_EN > 0
@@ -491,6 +488,22 @@ LW_WEAK VOID archWatchPointDectectHandle (addr_t ulRetAddr)
CALL_BSP_EXC_HOOK(ptcbCur, ulRetAddr, SPARC_TRAP_WDOG);
}
/*********************************************************************************************************
+** 函数名称: archUnalignedHandle
+** 功能描述: 非对齐内存访问异常处理
+** 输 入 : pabtctx abort 上下文
+** 输 出 : NONE
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static VOID archUnalignedHandle (PLW_VMM_ABORT_CTX pabtctx)
+{
+ sparcUnalignedHandle(&pabtctx->ABTCTX_archRegCtx,
+ &pabtctx->ABTCTX_ulAbortAddr,
+ &pabtctx->ABTCTX_abtInfo);
+
+ API_VmmAbortReturn(pabtctx);
+}
+/*********************************************************************************************************
** 函数名称: archMemAddrNoAlignHandle
** 功能描述: A load/store instruction would have generated a memory address that was not
** properly aligned according to the instruction, or a JMPL or RETT instruction
@@ -504,17 +517,15 @@ VOID archMemAddrNoAlignHandle (addr_t ulRetAddr, ARCH_REG_CTX *pregctx)
{
PLW_CLASS_TCB ptcbCur;
LW_VMM_ABORT abtInfo;
- addr_t ulAbortAddr;
+ addr_t ulAbortAddr = ulRetAddr; /* 终止地址在分析指令才能得到 */
LW_TCB_GET_CUR(ptcbCur);
CALL_BSP_EXC_HOOK(ptcbCur, ulRetAddr, SPARC_TRAP_MNA);
- abtInfo.VMABT_uiType = sparcUnalignedHandle(pregctx,
- &ulAbortAddr, &abtInfo.VMABT_uiMethod);
- if (abtInfo.VMABT_uiType) {
- API_VmmAbortIsr(ulRetAddr, ulAbortAddr, &abtInfo, ptcbCur);
- }
+ abtInfo.VMABT_uiType = LW_VMM_ABORT_TYPE_BUS;
+ abtInfo.VMABT_uiMethod = BUS_ADRALN;
+ API_VmmAbortIsrEx(ulRetAddr, ulAbortAddr, &abtInfo, ptcbCur, archUnalignedHandle);
}
/*********************************************************************************************************
** 函数名称: archFpExcHandle
diff --git a/SylixOS/arch/sparc/common/sparcUnaligned.c b/SylixOS/arch/sparc/common/unaligned/sparcUnaligned.c
index 538215d..84faf46 100644
--- a/SylixOS/arch/sparc/common/sparcUnaligned.c
+++ b/SylixOS/arch/sparc/common/unaligned/sparcUnaligned.c
@@ -164,12 +164,12 @@ static inline int floating_point_load_or_store_p(unsigned int insn)
** 功能描述: SPARC 非对齐处理
** 输 入 : pregctx 寄存器上下文
** pulAbortAddr 终止地址
-** puiMethod 终止方法
-** 输 出 : 终止类型
+** pabtInfo 终止信息
+** 输 出 : NONE
** 全局变量:
** 调用模块:
*********************************************************************************************************/
-UINT sparcUnalignedHandle (ARCH_REG_CTX *regs, addr_t *pulAbortAddr, UINT *puiMethod)
+VOID sparcUnalignedHandle (ARCH_REG_CTX *pregctx, addr_t *pulAbortAddr, PLW_VMM_ABORT pabtInfo)
{
SPARC_PARAM *param = archKernelParamGet();
UINT insn;
@@ -178,17 +178,16 @@ UINT sparcUnalignedHandle (ARCH_REG_CTX *regs, addr_t *pulAbortAddr, UINT *p
addr_t addr;
*pulAbortAddr = (addr_t)-1;
- *puiMethod = BUS_ADRALN;
- if ((regs->REG_uiPc | regs->REG_uiNPc) & 3) {
- *pulAbortAddr = regs->REG_uiPc;
- return (LW_VMM_ABORT_TYPE_BUS);
+ if ((pregctx->REG_uiPc | pregctx->REG_uiNPc) & 3) {
+ *pulAbortAddr = pregctx->REG_uiPc;
+ goto sigbus;
}
- insn = *(UINT *)regs->REG_uiPc;
+ insn = *(UINT *)pregctx->REG_uiPc;
if (((insn >> 30) & 3) != 3) {
- return (LW_VMM_ABORT_TYPE_BUS);
+ goto sigbus;
}
dir = decode_direction(insn);
@@ -196,37 +195,43 @@ UINT sparcUnalignedHandle (ARCH_REG_CTX *regs, addr_t *pulAbortAddr, UINT *p
if (size < 0) {
printk("Impossible unaligned trap. insn=%08x\n", insn);
printk("Byte sized unaligned access?!?!\n");
- return (LW_VMM_ABORT_TYPE_BUS);
+ goto sigbus;
}
if (floating_point_load_or_store_p(insn)) {
printk("User FPU load/store unaligned unsupported.\n");
- return (LW_VMM_ABORT_TYPE_BUS);
+ goto sigill;
}
- addr = compute_effective_address(regs, insn);
+ addr = compute_effective_address(pregctx, insn);
*pulAbortAddr = addr;
/*
* unsupport unalign access
*/
if (param->SPARC_bUnalign == LW_FALSE) {
- return (LW_VMM_ABORT_TYPE_BUS);
+ goto sigbus;
}
switch (dir) {
case load:
- err = do_int_load(fetch_reg_addr(((insn >> 25) & 0x1f), regs),
+ err = do_int_load(fetch_reg_addr(((insn >> 25) & 0x1f), pregctx),
size,
(unsigned long *)addr,
decode_signedness(insn));
+ if (err) {
+ goto sigbus;
+ }
break;
case store:
err = do_int_store(((insn >> 25) & 0x1f),
size,
(unsigned long *)addr,
- regs);
+ pregctx);
+ if (err) {
+ goto sigbus;
+ }
break;
case both:
@@ -234,22 +239,27 @@ UINT sparcUnalignedHandle (ARCH_REG_CTX *regs, addr_t *pulAbortAddr, UINT *p
* the value of SWAP instruction across word boundaries.
*/
printk("Unaligned SWAP unsupported.\n");
- err = -EFAULT;
+ goto sigill;
break;
default:
printk("Impossible user unaligned trap.\n");
- err = -EFAULT;
+ goto sigill;
break;
}
- if (err) {
- return (LW_VMM_ABORT_TYPE_BUS);
+ advance(pregctx);
+ pabtInfo->VMABT_uiType = LW_VMM_ABORT_TYPE_NOINFO;
+ return;
- } else {
- advance(regs);
- return (0);
- }
+sigbus:
+ pabtInfo->VMABT_uiType = LW_VMM_ABORT_TYPE_BUS;
+ pabtInfo->VMABT_uiMethod = BUS_ADRALN;
+ return;
+
+sigill:
+ pabtInfo->VMABT_uiType = LW_VMM_ABORT_TYPE_UNDEF;
+ pabtInfo->VMABT_uiMethod = LW_VMM_ABORT_METHOD_EXEC;
}
/*********************************************************************************************************
END
diff --git a/SylixOS/arch/sparc/common/unaligned/sparcUnaligned.h b/SylixOS/arch/sparc/common/unaligned/sparcUnaligned.h
new file mode 100644
index 0000000..232709d
--- /dev/null
+++ b/SylixOS/arch/sparc/common/unaligned/sparcUnaligned.h
@@ -0,0 +1,30 @@
+/*********************************************************************************************************
+**
+** 中国软件开源组织
+**
+** 嵌入式实时操作系统
+**
+** SylixOS(TM) LW : long wing
+**
+** Copyright All Rights Reserved
+**
+**--------------文件信息--------------------------------------------------------------------------------
+**
+** 文 件 名: sparcUnaligned.h
+**
+** 创 建 人: Jiao.JinXing (焦进星)
+**
+** 文件创建日期: 2018 年 11 月 16 日
+**
+** 描 述: SPARC 体系构架非对齐异常处理.
+*********************************************************************************************************/
+
+#ifndef __ARCH_SPARCUNALIGNED_H
+#define __ARCH_SPARCUNALIGNED_H
+
+VOID sparcUnalignedHandle(ARCH_REG_CTX *pregctx, addr_t *pulAbortAddr, PLW_VMM_ABORT pabtInfo);
+
+#endif /* __ARCH_SPARCUNALIGNED_H */
+/*********************************************************************************************************
+ END
+*********************************************************************************************************/
diff --git a/SylixOS/arch/sparc/common/sparcUnalignedAsm.S b/SylixOS/arch/sparc/common/unaligned/sparcUnalignedAsm.S
index ba9f491..ba9f491 100644
--- a/SylixOS/arch/sparc/common/sparcUnalignedAsm.S
+++ b/SylixOS/arch/sparc/common/unaligned/sparcUnalignedAsm.S
diff --git a/SylixOS/bintools/demangle/ansidecl.h b/SylixOS/bintools/demangle/ansidecl.h
new file mode 100644
index 0000000..0fb23bb
--- /dev/null
+++ b/SylixOS/bintools/demangle/ansidecl.h
@@ -0,0 +1,313 @@
+/* ANSI and traditional C compatability macros
+ Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
+ 2002, 2003, 2004, 2005, 2006, 2007, 2009, 2010, 2013
+ Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* ANSI and traditional C compatibility macros
+
+ ANSI C is assumed if __STDC__ is #defined.
+
+ Macro ANSI C definition Traditional C definition
+ ----- ---- - ---------- ----------- - ----------
+ PTR `void *' `char *'
+ const not defined `'
+ volatile not defined `'
+ signed not defined `'
+
+ For ease of writing code which uses GCC extensions but needs to be
+ portable to other compilers, we provide the GCC_VERSION macro that
+ simplifies testing __GNUC__ and __GNUC_MINOR__ together, and various
+ wrappers around __attribute__. Also, __extension__ will be #defined
+ to nothing if it doesn't work. See below. */
+
+#ifndef _ANSIDECL_H
+#define _ANSIDECL_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Every source file includes this file,
+ so they will all get the switch for lint. */
+/* LINTLIBRARY */
+
+/* Using MACRO(x,y) in cpp #if conditionals does not work with some
+ older preprocessors. Thus we can't define something like this:
+
+#define HAVE_GCC_VERSION(MAJOR, MINOR) \
+ (__GNUC__ > (MAJOR) || (__GNUC__ == (MAJOR) && __GNUC_MINOR__ >= (MINOR)))
+
+and then test "#if HAVE_GCC_VERSION(2,7)".
+
+So instead we use the macro below and test it against specific values. */
+
+/* This macro simplifies testing whether we are using gcc, and if it
+ is of a particular minimum version. (Both major & minor numbers are
+ significant.) This macro will evaluate to 0 if we are not using
+ gcc at all. */
+#ifndef GCC_VERSION
+#define GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__)
+#endif /* GCC_VERSION */
+
+#if defined (__STDC__) || defined(__cplusplus) || defined (_AIX) || (defined (__mips) && defined (_SYSTYPE_SVR4)) || defined(_WIN32)
+/* All known AIX compilers implement these things (but don't always
+ define __STDC__). The RISC/OS MIPS compiler defines these things
+ in SVR4 mode, but does not define __STDC__. */
+/* eraxxon@alumni.rice.edu: The Compaq C++ compiler, unlike many other
+ C++ compilers, does not define __STDC__, though it acts as if this
+ was so. (Verified versions: 5.7, 6.2, 6.3, 6.5) */
+
+#define PTR void *
+
+#undef const
+#undef volatile
+#undef signed
+
+/* inline requires special treatment; it's in C99, and GCC >=2.7 supports
+ it too, but it's not in C89. */
+#undef inline
+#if __STDC_VERSION__ >= 199901L || defined(__cplusplus) || (defined(__SUNPRO_C) && defined(__C99FEATURES__))
+/* it's a keyword */
+#else
+# if GCC_VERSION >= 2007
+# define inline __inline__ /* __inline__ prevents -pedantic warnings */
+# else
+# define inline /* nothing */
+# endif
+#endif
+
+#else /* Not ANSI C. */
+
+#define PTR char *
+
+/* some systems define these in header files for non-ansi mode */
+#undef const
+#undef volatile
+#undef signed
+#undef inline
+#define const
+#define volatile
+#define signed
+#define inline
+
+#endif /* ANSI C. */
+
+/* Define macros for some gcc attributes. This permits us to use the
+ macros freely, and know that they will come into play for the
+ version of gcc in which they are supported. */
+
+#if (GCC_VERSION < 2007)
+# define __attribute__(x)
+#endif
+
+/* Attribute __malloc__ on functions was valid as of gcc 2.96. */
+#ifndef ATTRIBUTE_MALLOC
+# if (GCC_VERSION >= 2096)
+# define ATTRIBUTE_MALLOC __attribute__ ((__malloc__))
+# else
+# define ATTRIBUTE_MALLOC
+# endif /* GNUC >= 2.96 */
+#endif /* ATTRIBUTE_MALLOC */
+
+/* Attributes on labels were valid as of gcc 2.93 and g++ 4.5. For
+ g++ an attribute on a label must be followed by a semicolon. */
+#ifndef ATTRIBUTE_UNUSED_LABEL
+# ifndef __cplusplus
+# if GCC_VERSION >= 2093
+# define ATTRIBUTE_UNUSED_LABEL ATTRIBUTE_UNUSED
+# else
+# define ATTRIBUTE_UNUSED_LABEL
+# endif
+# else
+# if GCC_VERSION >= 4005
+# define ATTRIBUTE_UNUSED_LABEL ATTRIBUTE_UNUSED ;
+# else
+# define ATTRIBUTE_UNUSED_LABEL
+# endif
+# endif
+#endif
+
+/* Similarly to ARG_UNUSED below. Prior to GCC 3.4, the C++ frontend
+ couldn't parse attributes placed after the identifier name, and now
+ the entire compiler is built with C++. */
+#ifndef ATTRIBUTE_UNUSED
+#if GCC_VERSION >= 3004
+# define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
+#else
+#define ATTRIBUTE_UNUSED
+#endif
+#endif /* ATTRIBUTE_UNUSED */
+
+/* Before GCC 3.4, the C++ frontend couldn't parse attributes placed after the
+ identifier name. */
+#if ! defined(__cplusplus) || (GCC_VERSION >= 3004)
+# define ARG_UNUSED(NAME) NAME ATTRIBUTE_UNUSED
+#else /* !__cplusplus || GNUC >= 3.4 */
+# define ARG_UNUSED(NAME) NAME
+#endif /* !__cplusplus || GNUC >= 3.4 */
+
+#ifndef ATTRIBUTE_NORETURN
+#define ATTRIBUTE_NORETURN __attribute__ ((__noreturn__))
+#endif /* ATTRIBUTE_NORETURN */
+
+/* Attribute `nonnull' was valid as of gcc 3.3. */
+#ifndef ATTRIBUTE_NONNULL
+# if (GCC_VERSION >= 3003)
+# define ATTRIBUTE_NONNULL(m) __attribute__ ((__nonnull__ (m)))
+# else
+# define ATTRIBUTE_NONNULL(m)
+# endif /* GNUC >= 3.3 */
+#endif /* ATTRIBUTE_NONNULL */
+
+/* Attribute `returns_nonnull' was valid as of gcc 4.9. */
+#ifndef ATTRIBUTE_RETURNS_NONNULL
+# if (GCC_VERSION >= 4009)
+# define ATTRIBUTE_RETURNS_NONNULL __attribute__ ((__returns_nonnull__))
+# else
+# define ATTRIBUTE_RETURNS_NONNULL
+# endif /* GNUC >= 4.9 */
+#endif /* ATTRIBUTE_RETURNS_NONNULL */
+
+/* Attribute `pure' was valid as of gcc 3.0. */
+#ifndef ATTRIBUTE_PURE
+# if (GCC_VERSION >= 3000)
+# define ATTRIBUTE_PURE __attribute__ ((__pure__))
+# else
+# define ATTRIBUTE_PURE
+# endif /* GNUC >= 3.0 */
+#endif /* ATTRIBUTE_PURE */
+
+/* Use ATTRIBUTE_PRINTF when the format specifier must not be NULL.
+ This was the case for the `printf' format attribute by itself
+ before GCC 3.3, but as of 3.3 we need to add the `nonnull'
+ attribute to retain this behavior. */
+#ifndef ATTRIBUTE_PRINTF
+#define ATTRIBUTE_PRINTF(m, n) __attribute__ ((__format__ (__printf__, m, n))) ATTRIBUTE_NONNULL(m)
+#define ATTRIBUTE_PRINTF_1 ATTRIBUTE_PRINTF(1, 2)
+#define ATTRIBUTE_PRINTF_2 ATTRIBUTE_PRINTF(2, 3)
+#define ATTRIBUTE_PRINTF_3 ATTRIBUTE_PRINTF(3, 4)
+#define ATTRIBUTE_PRINTF_4 ATTRIBUTE_PRINTF(4, 5)
+#define ATTRIBUTE_PRINTF_5 ATTRIBUTE_PRINTF(5, 6)
+#endif /* ATTRIBUTE_PRINTF */
+
+/* Use ATTRIBUTE_FPTR_PRINTF when the format attribute is to be set on
+ a function pointer. Format attributes were allowed on function
+ pointers as of gcc 3.1. */
+#ifndef ATTRIBUTE_FPTR_PRINTF
+# if (GCC_VERSION >= 3001)
+# define ATTRIBUTE_FPTR_PRINTF(m, n) ATTRIBUTE_PRINTF(m, n)
+# else
+# define ATTRIBUTE_FPTR_PRINTF(m, n)
+# endif /* GNUC >= 3.1 */
+# define ATTRIBUTE_FPTR_PRINTF_1 ATTRIBUTE_FPTR_PRINTF(1, 2)
+# define ATTRIBUTE_FPTR_PRINTF_2 ATTRIBUTE_FPTR_PRINTF(2, 3)
+# define ATTRIBUTE_FPTR_PRINTF_3 ATTRIBUTE_FPTR_PRINTF(3, 4)
+# define ATTRIBUTE_FPTR_PRINTF_4 ATTRIBUTE_FPTR_PRINTF(4, 5)
+# define ATTRIBUTE_FPTR_PRINTF_5 ATTRIBUTE_FPTR_PRINTF(5, 6)
+#endif /* ATTRIBUTE_FPTR_PRINTF */
+
+/* Use ATTRIBUTE_NULL_PRINTF when the format specifier may be NULL. A
+ NULL format specifier was allowed as of gcc 3.3. */
+#ifndef ATTRIBUTE_NULL_PRINTF
+# if (GCC_VERSION >= 3003)
+# define ATTRIBUTE_NULL_PRINTF(m, n) __attribute__ ((__format__ (__printf__, m, n)))
+# else
+# define ATTRIBUTE_NULL_PRINTF(m, n)
+# endif /* GNUC >= 3.3 */
+# define ATTRIBUTE_NULL_PRINTF_1 ATTRIBUTE_NULL_PRINTF(1, 2)
+# define ATTRIBUTE_NULL_PRINTF_2 ATTRIBUTE_NULL_PRINTF(2, 3)
+# define ATTRIBUTE_NULL_PRINTF_3 ATTRIBUTE_NULL_PRINTF(3, 4)
+# define ATTRIBUTE_NULL_PRINTF_4 ATTRIBUTE_NULL_PRINTF(4, 5)
+# define ATTRIBUTE_NULL_PRINTF_5 ATTRIBUTE_NULL_PRINTF(5, 6)
+#endif /* ATTRIBUTE_NULL_PRINTF */
+
+/* Attribute `sentinel' was valid as of gcc 3.5. */
+#ifndef ATTRIBUTE_SENTINEL
+# if (GCC_VERSION >= 3005)
+# define ATTRIBUTE_SENTINEL __attribute__ ((__sentinel__))
+# else
+# define ATTRIBUTE_SENTINEL
+# endif /* GNUC >= 3.5 */
+#endif /* ATTRIBUTE_SENTINEL */
+
+
+#ifndef ATTRIBUTE_ALIGNED_ALIGNOF
+# if (GCC_VERSION >= 3000)
+# define ATTRIBUTE_ALIGNED_ALIGNOF(m) __attribute__ ((__aligned__ (__alignof__ (m))))
+# else
+# define ATTRIBUTE_ALIGNED_ALIGNOF(m)
+# endif /* GNUC >= 3.0 */
+#endif /* ATTRIBUTE_ALIGNED_ALIGNOF */
+
+/* Useful for structures whose layout must much some binary specification
+ regardless of the alignment and padding qualities of the compiler. */
+#ifndef ATTRIBUTE_PACKED
+# define ATTRIBUTE_PACKED __attribute__ ((packed))
+#endif
+
+/* Attribute `hot' and `cold' was valid as of gcc 4.3. */
+#ifndef ATTRIBUTE_COLD
+# if (GCC_VERSION >= 4003)
+# define ATTRIBUTE_COLD __attribute__ ((__cold__))
+# else
+# define ATTRIBUTE_COLD
+# endif /* GNUC >= 4.3 */
+#endif /* ATTRIBUTE_COLD */
+#ifndef ATTRIBUTE_HOT
+# if (GCC_VERSION >= 4003)
+# define ATTRIBUTE_HOT __attribute__ ((__hot__))
+# else
+# define ATTRIBUTE_HOT
+# endif /* GNUC >= 4.3 */
+#endif /* ATTRIBUTE_HOT */
+
+/* We use __extension__ in some places to suppress -pedantic warnings
+ about GCC extensions. This feature didn't work properly before
+ gcc 2.8. */
+#if GCC_VERSION < 2008
+#define __extension__
+#endif
+
+/* This is used to declare a const variable which should be visible
+ outside of the current compilation unit. Use it as
+ EXPORTED_CONST int i = 1;
+ This is because the semantics of const are different in C and C++.
+ "extern const" is permitted in C but it looks strange, and gcc
+ warns about it when -Wc++-compat is not used. */
+#ifdef __cplusplus
+#define EXPORTED_CONST extern const
+#else
+#define EXPORTED_CONST const
+#endif
+
+/* Be conservative and only use enum bitfields with C++ or GCC.
+ FIXME: provide a complete autoconf test for buggy enum bitfields. */
+
+#ifdef __cplusplus
+#define ENUM_BITFIELD(TYPE) enum TYPE
+#elif (GCC_VERSION > 2000)
+#define ENUM_BITFIELD(TYPE) __extension__ enum TYPE
+#else
+#define ENUM_BITFIELD(TYPE) unsigned int
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ansidecl.h */
diff --git a/SylixOS/bintools/demangle/cp-demangle.c b/SylixOS/bintools/demangle/cp-demangle.c
new file mode 100644
index 0000000..2acf46f
--- /dev/null
+++ b/SylixOS/bintools/demangle/cp-demangle.c
@@ -0,0 +1,6371 @@
+/* Demangler for g++ V3 ABI.
+ Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2014
+ Free Software Foundation, Inc.
+ Written by Ian Lance Taylor <ian@wasabisystems.com>.
+
+ This file is part of the libiberty library, which is part of GCC.
+
+ This file is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ In addition to the permissions in the GNU General Public License, the
+ Free Software Foundation gives you unlimited permission to link the
+ compiled version of this file into combinations with other programs,
+ and to distribute those combinations without any restriction coming
+ from the use of this file. (The General Public License restrictions
+ do apply in other respects; for example, they cover modification of
+ the file, and distribution when not linked into a combined
+ executable.)
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+/* This code implements a demangler for the g++ V3 ABI. The ABI is
+ described on this web page:
+ http://www.codesourcery.com/cxx-abi/abi.html#mangling
+
+ This code was written while looking at the demangler written by
+ Alex Samuel <samuel@codesourcery.com>.
+
+ This code first pulls the mangled name apart into a list of
+ components, and then walks the list generating the demangled
+ name.
+
+ This file will normally define the following functions, q.v.:
+ char *cplus_demangle_v3(const char *mangled, int options)
+ char *java_demangle_v3(const char *mangled)
+ int cplus_demangle_v3_callback(const char *mangled, int options,
+ demangle_callbackref callback)
+ int java_demangle_v3_callback(const char *mangled,
+ demangle_callbackref callback)
+ enum gnu_v3_ctor_kinds is_gnu_v3_mangled_ctor (const char *name)
+ enum gnu_v3_dtor_kinds is_gnu_v3_mangled_dtor (const char *name)
+
+ Also, the interface to the component list is public, and defined in
+ demangle.h. The interface consists of these types, which are
+ defined in demangle.h:
+ enum demangle_component_type
+ struct demangle_component
+ demangle_callbackref
+ and these functions defined in this file:
+ cplus_demangle_fill_name
+ cplus_demangle_fill_extended_operator
+ cplus_demangle_fill_ctor
+ cplus_demangle_fill_dtor
+ cplus_demangle_print
+ cplus_demangle_print_callback
+ and other functions defined in the file cp-demint.c.
+
+ This file also defines some other functions and variables which are
+ only to be used by the file cp-demint.c.
+
+ Preprocessor macros you can define while compiling this file:
+
+ IN_LIBGCC2
+ If defined, this file defines the following functions, q.v.:
+ char *__cxa_demangle (const char *mangled, char *buf, size_t *len,
+ int *status)
+ int __gcclibcxx_demangle_callback (const char *,
+ void (*)
+ (const char *, size_t, void *),
+ void *)
+ instead of cplus_demangle_v3[_callback]() and
+ java_demangle_v3[_callback]().
+
+ IN_GLIBCPP_V3
+ If defined, this file defines only __cxa_demangle() and
+ __gcclibcxx_demangle_callback(), and no other publically visible
+ functions or variables.
+
+ STANDALONE_DEMANGLER
+ If defined, this file defines a main() function which demangles
+ any arguments, or, if none, demangles stdin.
+
+ CP_DEMANGLE_DEBUG
+ If defined, turns on debugging mode, which prints information on
+ stdout about the mangled string. This is not generally useful.
+*/
+
+#include "SylixOS.h"
+
+/*
+ * configure options for SylixOS
+ */
+#define HAVE_STDLIB_H
+#define HAVE_STRING_H
+#define HAVE_ALLOCA_H
+#define IN_LIBGCC2
+
+/*
+ * undefine symbols on SylixOS
+ *
+ * $ nm -u cp-demangle.o
+ * U abort
+ * U free
+ * U memcmp
+ * U memcpy
+ * U realloc
+ * U sprintf
+ * U strcmp
+ * U strcpy
+ * U strlen
+ * U strncmp
+ */
+
+/*
+ * c6x librts.a has __cxa_demangle() function
+ */
+#if !defined(LW_CFG_CPU_ARCH_C6X) && (LW_CFG_MODULELOADER_EN > 0)
+
+#if defined (_AIX) && !defined (__GNUC__)
+ #pragma alloca
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#ifdef HAVE_ALLOCA_H
+# include <alloca.h>
+#else
+# ifndef alloca
+# ifdef __GNUC__
+# define alloca __builtin_alloca
+# else
+extern char *alloca ();
+# endif /* __GNUC__ */
+# endif /* alloca */
+#endif /* HAVE_ALLOCA_H */
+
+#include "ansidecl.h"
+#include "libiberty.h"
+#include "demangle.h"
+#include "cp-demangle.h"
+
+/* If IN_GLIBCPP_V3 is defined, some functions are made static. We
+ also rename them via #define to avoid compiler errors when the
+ static definition conflicts with the extern declaration in a header
+ file. */
+#ifdef IN_GLIBCPP_V3
+
+#define CP_STATIC_IF_GLIBCPP_V3 static
+
+#define cplus_demangle_fill_name d_fill_name
+static int d_fill_name (struct demangle_component *, const char *, int);
+
+#define cplus_demangle_fill_extended_operator d_fill_extended_operator
+static int
+d_fill_extended_operator (struct demangle_component *, int,
+ struct demangle_component *);
+
+#define cplus_demangle_fill_ctor d_fill_ctor
+static int
+d_fill_ctor (struct demangle_component *, enum gnu_v3_ctor_kinds,
+ struct demangle_component *);
+
+#define cplus_demangle_fill_dtor d_fill_dtor
+static int
+d_fill_dtor (struct demangle_component *, enum gnu_v3_dtor_kinds,
+ struct demangle_component *);
+
+#define cplus_demangle_mangled_name d_mangled_name
+static struct demangle_component *d_mangled_name (struct d_info *, int);
+
+#define cplus_demangle_type d_type
+static struct demangle_component *d_type (struct d_info *);
+
+#define cplus_demangle_print d_print
+static char *d_print (int, const struct demangle_component *, int, size_t *);
+
+#define cplus_demangle_print_callback d_print_callback
+static int d_print_callback (int, const struct demangle_component *,
+ demangle_callbackref, void *);
+
+#define cplus_demangle_init_info d_init_info
+static void d_init_info (const char *, int, size_t, struct d_info *);
+
+#else /* ! defined(IN_GLIBCPP_V3) */
+#define CP_STATIC_IF_GLIBCPP_V3
+#endif /* ! defined(IN_GLIBCPP_V3) */
+
+/* See if the compiler supports dynamic arrays. */
+
+#ifdef __GNUC__
+#define CP_DYNAMIC_ARRAYS
+#else
+#ifdef __STDC__
+#ifdef __STDC_VERSION__
+#if __STDC_VERSION__ >= 199901L
+#define CP_DYNAMIC_ARRAYS
+#endif /* __STDC__VERSION >= 199901L */
+#endif /* defined (__STDC_VERSION__) */
+#endif /* defined (__STDC__) */
+#endif /* ! defined (__GNUC__) */
+
+/* We avoid pulling in the ctype tables, to prevent pulling in
+ additional unresolved symbols when this code is used in a library.
+ FIXME: Is this really a valid reason? This comes from the original
+ V3 demangler code.
+
+ As of this writing this file has the following undefined references
+ when compiled with -DIN_GLIBCPP_V3: realloc, free, memcpy, strcpy,
+ strcat, strlen. */
+
+#define IS_DIGIT(c) ((c) >= '0' && (c) <= '9')
+#define IS_UPPER(c) ((c) >= 'A' && (c) <= 'Z')
+#define IS_LOWER(c) ((c) >= 'a' && (c) <= 'z')
+
+/* The prefix prepended by GCC to an identifier represnting the
+ anonymous namespace. */
+#define ANONYMOUS_NAMESPACE_PREFIX "_GLOBAL_"
+#define ANONYMOUS_NAMESPACE_PREFIX_LEN \
+ (sizeof (ANONYMOUS_NAMESPACE_PREFIX) - 1)
+
+/* Information we keep for the standard substitutions. */
+
+struct d_standard_sub_info
+{
+ /* The code for this substitution. */
+ char code;
+ /* The simple string it expands to. */
+ const char *simple_expansion;
+ /* The length of the simple expansion. */
+ int simple_len;
+ /* The results of a full, verbose, expansion. This is used when
+ qualifying a constructor/destructor, or when in verbose mode. */
+ const char *full_expansion;
+ /* The length of the full expansion. */
+ int full_len;
+ /* What to set the last_name field of d_info to; NULL if we should
+ not set it. This is only relevant when qualifying a
+ constructor/destructor. */
+ const char *set_last_name;
+ /* The length of set_last_name. */
+ int set_last_name_len;
+};
+
+/* Accessors for subtrees of struct demangle_component. */
+
+#define d_left(dc) ((dc)->u.s_binary.left)
+#define d_right(dc) ((dc)->u.s_binary.right)
+
+/* A list of templates. This is used while printing. */
+
+struct d_print_template
+{
+ /* Next template on the list. */
+ struct d_print_template *next;
+ /* This template. */
+ const struct demangle_component *template_decl;
+};
+
+/* A list of type modifiers. This is used while printing. */
+
+struct d_print_mod
+{
+ /* Next modifier on the list. These are in the reverse of the order
+ in which they appeared in the mangled string. */
+ struct d_print_mod *next;
+ /* The modifier. */
+ const struct demangle_component *mod;
+ /* Whether this modifier was printed. */
+ int printed;
+ /* The list of templates which applies to this modifier. */
+ struct d_print_template *templates;
+};
+
+/* We use these structures to hold information during printing. */
+
+struct d_growable_string
+{
+ /* Buffer holding the result. */
+ char *buf;
+ /* Current length of data in buffer. */
+ size_t len;
+ /* Allocated size of buffer. */
+ size_t alc;
+ /* Set to 1 if we had a memory allocation failure. */
+ int allocation_failure;
+};
+
+/* A demangle component and some scope captured when it was first
+ traversed. */
+
+struct d_saved_scope
+{
+ /* The component whose scope this is. */
+ const struct demangle_component *container;
+ /* The list of templates, if any, that was current when this
+ scope was captured. */
+ struct d_print_template *templates;
+};
+
+/* Checkpoint structure to allow backtracking. This holds copies
+ of the fields of struct d_info that need to be restored
+ if a trial parse needs to be backtracked over. */
+
+struct d_info_checkpoint
+{
+ const char *n;
+ int next_comp;
+ int next_sub;
+ int did_subs;
+ int expansion;
+};
+
+enum { D_PRINT_BUFFER_LENGTH = 256 };
+struct d_print_info
+{
+ /* Fixed-length allocated buffer for demangled data, flushed to the
+ callback with a NUL termination once full. */
+ char buf[D_PRINT_BUFFER_LENGTH];
+ /* Current length of data in buffer. */
+ size_t len;
+ /* The last character printed, saved individually so that it survives
+ any buffer flush. */
+ char last_char;
+ /* Callback function to handle demangled buffer flush. */
+ demangle_callbackref callback;
+ /* Opaque callback argument. */
+ void *opaque;
+ /* The current list of templates, if any. */
+ struct d_print_template *templates;
+ /* The current list of modifiers (e.g., pointer, reference, etc.),
+ if any. */
+ struct d_print_mod *modifiers;
+ /* Set to 1 if we saw a demangling error. */
+ int demangle_failure;
+ /* The current index into any template argument packs we are using
+ for printing. */
+ int pack_index;
+ /* Number of d_print_flush calls so far. */
+ unsigned long int flush_count;
+ /* Array of saved scopes for evaluating substitutions. */
+ struct d_saved_scope *saved_scopes;
+ /* Index of the next unused saved scope in the above array. */
+ int next_saved_scope;
+ /* Number of saved scopes in the above array. */
+ int num_saved_scopes;
+ /* Array of templates for saving into scopes. */
+ struct d_print_template *copy_templates;
+ /* Index of the next unused copy template in the above array. */
+ int next_copy_template;
+ /* Number of copy templates in the above array. */
+ int num_copy_templates;
+ /* The nearest enclosing template, if any. */
+ const struct demangle_component *current_template;
+};
+
+#ifdef CP_DEMANGLE_DEBUG
+static void d_dump (struct demangle_component *, int);
+#endif
+
+static struct demangle_component *
+d_make_empty (struct d_info *);
+
+static struct demangle_component *
+d_make_comp (struct d_info *, enum demangle_component_type,
+ struct demangle_component *,
+ struct demangle_component *);
+
+static struct demangle_component *
+d_make_name (struct d_info *, const char *, int);
+
+static struct demangle_component *
+d_make_demangle_mangled_name (struct d_info *, const char *);
+
+static struct demangle_component *
+d_make_builtin_type (struct d_info *,
+ const struct demangle_builtin_type_info *);
+
+static struct demangle_component *
+d_make_operator (struct d_info *,
+ const struct demangle_operator_info *);
+
+static struct demangle_component *
+d_make_extended_operator (struct d_info *, int,
+ struct demangle_component *);
+
+static struct demangle_component *
+d_make_ctor (struct d_info *, enum gnu_v3_ctor_kinds,
+ struct demangle_component *);
+
+static struct demangle_component *
+d_make_dtor (struct d_info *, enum gnu_v3_dtor_kinds,
+ struct demangle_component *);
+
+static struct demangle_component *
+d_make_template_param (struct d_info *, long);
+
+static struct demangle_component *
+d_make_sub (struct d_info *, const char *, int);
+
+static int
+has_return_type (struct demangle_component *);
+
+static int
+is_ctor_dtor_or_conversion (struct demangle_component *);
+
+static struct demangle_component *d_encoding (struct d_info *, int);
+
+static struct demangle_component *d_name (struct d_info *);
+
+static struct demangle_component *d_nested_name (struct d_info *);
+
+static struct demangle_component *d_prefix (struct d_info *);
+
+static struct demangle_component *d_unqualified_name (struct d_info *);
+
+static struct demangle_component *d_source_name (struct d_info *);
+
+static long d_number (struct d_info *);
+
+static struct demangle_component *d_identifier (struct d_info *, int);
+
+static struct demangle_component *d_operator_name (struct d_info *);
+
+static struct demangle_component *d_special_name (struct d_info *);
+
+static int d_call_offset (struct d_info *, int);
+
+static struct demangle_component *d_ctor_dtor_name (struct d_info *);
+
+static struct demangle_component **
+d_cv_qualifiers (struct d_info *, struct demangle_component **, int);
+
+static struct demangle_component *
+d_ref_qualifier (struct d_info *, struct demangle_component *);
+
+static struct demangle_component *
+d_function_type (struct d_info *);
+
+static struct demangle_component *
+d_bare_function_type (struct d_info *, int);
+
+static struct demangle_component *
+d_class_enum_type (struct d_info *);
+
+static struct demangle_component *d_array_type (struct d_info *);
+
+static struct demangle_component *d_vector_type (struct d_info *);
+
+static struct demangle_component *
+d_pointer_to_member_type (struct d_info *);
+
+static struct demangle_component *
+d_template_param (struct d_info *);
+
+static struct demangle_component *d_template_args (struct d_info *);
+
+static struct demangle_component *
+d_template_arg (struct d_info *);
+
+static struct demangle_component *d_expression (struct d_info *);
+
+static struct demangle_component *d_expr_primary (struct d_info *);
+
+static struct demangle_component *d_local_name (struct d_info *);
+
+static int d_discriminator (struct d_info *);
+
+static struct demangle_component *d_lambda (struct d_info *);
+
+static struct demangle_component *d_unnamed_type (struct d_info *);
+
+static struct demangle_component *
+d_clone_suffix (struct d_info *, struct demangle_component *);
+
+static int
+d_add_substitution (struct d_info *, struct demangle_component *);
+
+static struct demangle_component *d_substitution (struct d_info *, int);
+
+static void d_checkpoint (struct d_info *, struct d_info_checkpoint *);
+
+static void d_backtrack (struct d_info *, struct d_info_checkpoint *);
+
+static void d_growable_string_init (struct d_growable_string *, size_t);
+
+static inline void
+d_growable_string_resize (struct d_growable_string *, size_t);
+
+static inline void
+d_growable_string_append_buffer (struct d_growable_string *,
+ const char *, size_t);
+static void
+d_growable_string_callback_adapter (const char *, size_t, void *);
+
+static void
+d_print_init (struct d_print_info *, demangle_callbackref, void *,
+ const struct demangle_component *);
+
+static inline void d_print_error (struct d_print_info *);
+
+static inline int d_print_saw_error (struct d_print_info *);
+
+static inline void d_print_flush (struct d_print_info *);
+
+static inline void d_append_char (struct d_print_info *, char);
+
+static inline void d_append_buffer (struct d_print_info *,
+ const char *, size_t);
+
+static inline void d_append_string (struct d_print_info *, const char *);
+
+static inline char d_last_char (struct d_print_info *);
+
+static void
+d_print_comp (struct d_print_info *, int, const struct demangle_component *);
+
+static void
+d_print_java_identifier (struct d_print_info *, const char *, int);
+
+static void
+d_print_mod_list (struct d_print_info *, int, struct d_print_mod *, int);
+
+static void
+d_print_mod (struct d_print_info *, int, const struct demangle_component *);
+
+static void
+d_print_function_type (struct d_print_info *, int,
+ const struct demangle_component *,
+ struct d_print_mod *);
+
+static void
+d_print_array_type (struct d_print_info *, int,
+ const struct demangle_component *,
+ struct d_print_mod *);
+
+static void
+d_print_expr_op (struct d_print_info *, int, const struct demangle_component *);
+
+static void
+d_print_cast (struct d_print_info *, int, const struct demangle_component *);
+
+static int d_demangle_callback (const char *, int,
+ demangle_callbackref, void *);
+static char *d_demangle (const char *, int, size_t *);
+
+#ifdef CP_DEMANGLE_DEBUG
+
+static void
+d_dump (struct demangle_component *dc, int indent)
+{
+ int i;
+
+ if (dc == NULL)
+ {
+ if (indent == 0)
+ printf ("failed demangling\n");
+ return;
+ }
+
+ for (i = 0; i < indent; ++i)
+ putchar (' ');
+
+ switch (dc->type)
+ {
+ case DEMANGLE_COMPONENT_NAME:
+ printf ("name '%.*s'\n", dc->u.s_name.len, dc->u.s_name.s);
+ return;
+ case DEMANGLE_COMPONENT_TAGGED_NAME:
+ printf ("tagged name\n");
+ d_dump (dc->u.s_binary.left, indent + 2);
+ d_dump (dc->u.s_binary.right, indent + 2);
+ return;
+ case DEMANGLE_COMPONENT_TEMPLATE_PARAM:
+ printf ("template parameter %ld\n", dc->u.s_number.number);
+ return;
+ case DEMANGLE_COMPONENT_CTOR:
+ printf ("constructor %d\n", (int) dc->u.s_ctor.kind);
+ d_dump (dc->u.s_ctor.name, indent + 2);
+ return;
+ case DEMANGLE_COMPONENT_DTOR:
+ printf ("destructor %d\n", (int) dc->u.s_dtor.kind);
+ d_dump (dc->u.s_dtor.name, indent + 2);
+ return;
+ case DEMANGLE_COMPONENT_SUB_STD:
+ printf ("standard substitution %s\n", dc->u.s_string.string);
+ return;
+ case DEMANGLE_COMPONENT_BUILTIN_TYPE:
+ printf ("builtin type %s\n", dc->u.s_builtin.type->name);
+ return;
+ case DEMANGLE_COMPONENT_OPERATOR:
+ printf ("operator %s\n", dc->u.s_operator.op->name);
+ return;
+ case DEMANGLE_COMPONENT_EXTENDED_OPERATOR:
+ printf ("extended operator with %d args\n",
+ dc->u.s_extended_operator.args);
+ d_dump (dc->u.s_extended_operator.name, indent + 2);
+ return;
+
+ case DEMANGLE_COMPONENT_QUAL_NAME:
+ printf ("qualified name\n");
+ break;
+ case DEMANGLE_COMPONENT_LOCAL_NAME:
+ printf ("local name\n");
+ break;
+ case DEMANGLE_COMPONENT_TYPED_NAME:
+ printf ("typed name\n");
+ break;
+ case DEMANGLE_COMPONENT_TEMPLATE:
+ printf ("template\n");
+ break;
+ case DEMANGLE_COMPONENT_VTABLE:
+ printf ("vtable\n");
+ break;
+ case DEMANGLE_COMPONENT_VTT:
+ printf ("VTT\n");
+ break;
+ case DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE:
+ printf ("construction vtable\n");
+ break;
+ case DEMANGLE_COMPONENT_TYPEINFO:
+ printf ("typeinfo\n");
+ break;
+ case DEMANGLE_COMPONENT_TYPEINFO_NAME:
+ printf ("typeinfo name\n");
+ break;
+ case DEMANGLE_COMPONENT_TYPEINFO_FN:
+ printf ("typeinfo function\n");
+ break;
+ case DEMANGLE_COMPONENT_THUNK:
+ printf ("thunk\n");
+ break;
+ case DEMANGLE_COMPONENT_VIRTUAL_THUNK:
+ printf ("virtual thunk\n");
+ break;
+ case DEMANGLE_COMPONENT_COVARIANT_THUNK:
+ printf ("covariant thunk\n");
+ break;
+ case DEMANGLE_COMPONENT_JAVA_CLASS:
+ printf ("java class\n");
+ break;
+ case DEMANGLE_COMPONENT_GUARD:
+ printf ("guard\n");
+ break;
+ case DEMANGLE_COMPONENT_REFTEMP:
+ printf ("reference temporary\n");
+ break;
+ case DEMANGLE_COMPONENT_HIDDEN_ALIAS:
+ printf ("hidden alias\n");
+ break;
+ case DEMANGLE_COMPONENT_TRANSACTION_CLONE:
+ printf ("transaction clone\n");
+ break;
+ case DEMANGLE_COMPONENT_NONTRANSACTION_CLONE:
+ printf ("non-transaction clone\n");
+ break;
+ case DEMANGLE_COMPONENT_RESTRICT:
+ printf ("restrict\n");
+ break;
+ case DEMANGLE_COMPONENT_VOLATILE:
+ printf ("volatile\n");
+ break;
+ case DEMANGLE_COMPONENT_CONST:
+ printf ("const\n");
+ break;
+ case DEMANGLE_COMPONENT_RESTRICT_THIS:
+ printf ("restrict this\n");
+ break;
+ case DEMANGLE_COMPONENT_VOLATILE_THIS:
+ printf ("volatile this\n");
+ break;
+ case DEMANGLE_COMPONENT_CONST_THIS:
+ printf ("const this\n");
+ break;
+ case DEMANGLE_COMPONENT_REFERENCE_THIS:
+ printf ("reference this\n");
+ break;
+ case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS:
+ printf ("rvalue reference this\n");
+ break;
+ case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL:
+ printf ("vendor type qualifier\n");
+ break;
+ case DEMANGLE_COMPONENT_POINTER:
+ printf ("pointer\n");
+ break;
+ case DEMANGLE_COMPONENT_REFERENCE:
+ printf ("reference\n");
+ break;
+ case DEMANGLE_COMPONENT_RVALUE_REFERENCE:
+ printf ("rvalue reference\n");
+ break;
+ case DEMANGLE_COMPONENT_COMPLEX:
+ printf ("complex\n");
+ break;
+ case DEMANGLE_COMPONENT_IMAGINARY:
+ printf ("imaginary\n");
+ break;
+ case DEMANGLE_COMPONENT_VENDOR_TYPE:
+ printf ("vendor type\n");
+ break;
+ case DEMANGLE_COMPONENT_FUNCTION_TYPE:
+ printf ("function type\n");
+ break;
+ case DEMANGLE_COMPONENT_ARRAY_TYPE:
+ printf ("array type\n");
+ break;
+ case DEMANGLE_COMPONENT_PTRMEM_TYPE:
+ printf ("pointer to member type\n");
+ break;
+ case DEMANGLE_COMPONENT_FIXED_TYPE:
+ printf ("fixed-point type\n");
+ break;
+ case DEMANGLE_COMPONENT_ARGLIST:
+ printf ("argument list\n");
+ break;
+ case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST:
+ printf ("template argument list\n");
+ break;
+ case DEMANGLE_COMPONENT_INITIALIZER_LIST:
+ printf ("initializer list\n");
+ break;
+ case DEMANGLE_COMPONENT_CAST:
+ printf ("cast\n");
+ break;
+ case DEMANGLE_COMPONENT_NULLARY:
+ printf ("nullary operator\n");
+ break;
+ case DEMANGLE_COMPONENT_UNARY:
+ printf ("unary operator\n");
+ break;
+ case DEMANGLE_COMPONENT_BINARY:
+ printf ("binary operator\n");
+ break;
+ case DEMANGLE_COMPONENT_BINARY_ARGS:
+ printf ("binary operator arguments\n");
+ break;
+ case DEMANGLE_COMPONENT_TRINARY:
+ printf ("trinary operator\n");
+ break;
+ case DEMANGLE_COMPONENT_TRINARY_ARG1:
+ printf ("trinary operator arguments 1\n");
+ break;
+ case DEMANGLE_COMPONENT_TRINARY_ARG2:
+ printf ("trinary operator arguments 1\n");
+ break;
+ case DEMANGLE_COMPONENT_LITERAL:
+ printf ("literal\n");
+ break;
+ case DEMANGLE_COMPONENT_LITERAL_NEG:
+ printf ("negative literal\n");
+ break;
+ case DEMANGLE_COMPONENT_JAVA_RESOURCE:
+ printf ("java resource\n");
+ break;
+ case DEMANGLE_COMPONENT_COMPOUND_NAME:
+ printf ("compound name\n");
+ break;
+ case DEMANGLE_COMPONENT_CHARACTER:
+ printf ("character '%c'\n", dc->u.s_character.character);
+ return;
+ case DEMANGLE_COMPONENT_DECLTYPE:
+ printf ("decltype\n");
+ break;
+ case DEMANGLE_COMPONENT_PACK_EXPANSION:
+ printf ("pack expansion\n");
+ break;
+ case DEMANGLE_COMPONENT_TLS_INIT:
+ printf ("tls init function\n");
+ break;
+ case DEMANGLE_COMPONENT_TLS_WRAPPER:
+ printf ("tls wrapper function\n");
+ break;
+ case DEMANGLE_COMPONENT_DEFAULT_ARG:
+ printf ("default argument %d\n", dc->u.s_unary_num.num);
+ d_dump (dc->u.s_unary_num.sub, indent+2);
+ return;
+ case DEMANGLE_COMPONENT_LAMBDA:
+ printf ("lambda %d\n", dc->u.s_unary_num.num);
+ d_dump (dc->u.s_unary_num.sub, indent+2);
+ return;
+ }
+
+ d_dump (d_left (dc), indent + 2);
+ d_dump (d_right (dc), indent + 2);
+}
+
+#endif /* CP_DEMANGLE_DEBUG */
+
+/* Fill in a DEMANGLE_COMPONENT_NAME. */
+
+CP_STATIC_IF_GLIBCPP_V3
+int
+cplus_demangle_fill_name (struct demangle_component *p, const char *s, int len)
+{
+ if (p == NULL || s == NULL || len == 0)
+ return 0;
+ p->type = DEMANGLE_COMPONENT_NAME;
+ p->u.s_name.s = s;
+ p->u.s_name.len = len;
+ return 1;
+}
+
+/* Fill in a DEMANGLE_COMPONENT_EXTENDED_OPERATOR. */
+
+CP_STATIC_IF_GLIBCPP_V3
+int
+cplus_demangle_fill_extended_operator (struct demangle_component *p, int args,
+ struct demangle_component *name)
+{
+ if (p == NULL || args < 0 || name == NULL)
+ return 0;
+ p->type = DEMANGLE_COMPONENT_EXTENDED_OPERATOR;
+ p->u.s_extended_operator.args = args;
+ p->u.s_extended_operator.name = name;
+ return 1;
+}
+
+/* Fill in a DEMANGLE_COMPONENT_CTOR. */
+
+CP_STATIC_IF_GLIBCPP_V3
+int
+cplus_demangle_fill_ctor (struct demangle_component *p,
+ enum gnu_v3_ctor_kinds kind,
+ struct demangle_component *name)
+{
+ if (p == NULL
+ || name == NULL
+ || (int) kind < gnu_v3_complete_object_ctor
+ || (int) kind > gnu_v3_object_ctor_group)
+ return 0;
+ p->type = DEMANGLE_COMPONENT_CTOR;
+ p->u.s_ctor.kind = kind;
+ p->u.s_ctor.name = name;
+ return 1;
+}
+
+/* Fill in a DEMANGLE_COMPONENT_DTOR. */
+
+CP_STATIC_IF_GLIBCPP_V3
+int
+cplus_demangle_fill_dtor (struct demangle_component *p,
+ enum gnu_v3_dtor_kinds kind,
+ struct demangle_component *name)
+{
+ if (p == NULL
+ || name == NULL
+ || (int) kind < gnu_v3_deleting_dtor
+ || (int) kind > gnu_v3_object_dtor_group)
+ return 0;
+ p->type = DEMANGLE_COMPONENT_DTOR;
+ p->u.s_dtor.kind = kind;
+ p->u.s_dtor.name = name;
+ return 1;
+}
+
+/* Add a new component. */
+
+static struct demangle_component *
+d_make_empty (struct d_info *di)
+{
+ struct demangle_component *p;
+
+ if (di->next_comp >= di->num_comps)
+ return NULL;
+ p = &di->comps[di->next_comp];
+ ++di->next_comp;
+ return p;
+}
+
+/* Add a new generic component. */
+
+static struct demangle_component *
+d_make_comp (struct d_info *di, enum demangle_component_type type,
+ struct demangle_component *left,
+ struct demangle_component *right)
+{
+ struct demangle_component *p;
+
+ /* We check for errors here. A typical error would be a NULL return
+ from a subroutine. We catch those here, and return NULL
+ upward. */
+ switch (type)
+ {
+ /* These types require two parameters. */
+ case DEMANGLE_COMPONENT_QUAL_NAME:
+ case DEMANGLE_COMPONENT_LOCAL_NAME:
+ case DEMANGLE_COMPONENT_TYPED_NAME:
+ case DEMANGLE_COMPONENT_TAGGED_NAME:
+ case DEMANGLE_COMPONENT_TEMPLATE:
+ case DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE:
+ case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL:
+ case DEMANGLE_COMPONENT_PTRMEM_TYPE:
+ case DEMANGLE_COMPONENT_UNARY:
+ case DEMANGLE_COMPONENT_BINARY:
+ case DEMANGLE_COMPONENT_BINARY_ARGS:
+ case DEMANGLE_COMPONENT_TRINARY:
+ case DEMANGLE_COMPONENT_TRINARY_ARG1:
+ case DEMANGLE_COMPONENT_LITERAL:
+ case DEMANGLE_COMPONENT_LITERAL_NEG:
+ case DEMANGLE_COMPONENT_COMPOUND_NAME:
+ case DEMANGLE_COMPONENT_VECTOR_TYPE:
+ case DEMANGLE_COMPONENT_CLONE:
+ if (left == NULL || right == NULL)
+ return NULL;
+ break;
+
+ /* These types only require one parameter. */
+ case DEMANGLE_COMPONENT_VTABLE:
+ case DEMANGLE_COMPONENT_VTT:
+ case DEMANGLE_COMPONENT_TYPEINFO:
+ case DEMANGLE_COMPONENT_TYPEINFO_NAME:
+ case DEMANGLE_COMPONENT_TYPEINFO_FN:
+ case DEMANGLE_COMPONENT_THUNK:
+ case DEMANGLE_COMPONENT_VIRTUAL_THUNK:
+ case DEMANGLE_COMPONENT_COVARIANT_THUNK:
+ case DEMANGLE_COMPONENT_JAVA_CLASS:
+ case DEMANGLE_COMPONENT_GUARD:
+ case DEMANGLE_COMPONENT_TLS_INIT:
+ case DEMANGLE_COMPONENT_TLS_WRAPPER:
+ case DEMANGLE_COMPONENT_REFTEMP:
+ case DEMANGLE_COMPONENT_HIDDEN_ALIAS:
+ case DEMANGLE_COMPONENT_TRANSACTION_CLONE:
+ case DEMANGLE_COMPONENT_NONTRANSACTION_CLONE:
+ case DEMANGLE_COMPONENT_POINTER:
+ case DEMANGLE_COMPONENT_REFERENCE:
+ case DEMANGLE_COMPONENT_RVALUE_REFERENCE:
+ case DEMANGLE_COMPONENT_COMPLEX:
+ case DEMANGLE_COMPONENT_IMAGINARY:
+ case DEMANGLE_COMPONENT_VENDOR_TYPE:
+ case DEMANGLE_COMPONENT_CAST:
+ case DEMANGLE_COMPONENT_JAVA_RESOURCE:
+ case DEMANGLE_COMPONENT_DECLTYPE:
+ case DEMANGLE_COMPONENT_PACK_EXPANSION:
+ case DEMANGLE_COMPONENT_GLOBAL_CONSTRUCTORS:
+ case DEMANGLE_COMPONENT_GLOBAL_DESTRUCTORS:
+ case DEMANGLE_COMPONENT_NULLARY:
+ case DEMANGLE_COMPONENT_TRINARY_ARG2:
+ if (left == NULL)
+ return NULL;
+ break;
+
+ /* This needs a right parameter, but the left parameter can be
+ empty. */
+ case DEMANGLE_COMPONENT_ARRAY_TYPE:
+ case DEMANGLE_COMPONENT_INITIALIZER_LIST:
+ if (right == NULL)
+ return NULL;
+ break;
+
+ /* These are allowed to have no parameters--in some cases they
+ will be filled in later. */
+ case DEMANGLE_COMPONENT_FUNCTION_TYPE:
+ case DEMANGLE_COMPONENT_RESTRICT:
+ case DEMANGLE_COMPONENT_VOLATILE:
+ case DEMANGLE_COMPONENT_CONST:
+ case DEMANGLE_COMPONENT_RESTRICT_THIS:
+ case DEMANGLE_COMPONENT_VOLATILE_THIS:
+ case DEMANGLE_COMPONENT_CONST_THIS:
+ case DEMANGLE_COMPONENT_REFERENCE_THIS:
+ case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS:
+ case DEMANGLE_COMPONENT_ARGLIST:
+ case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST:
+ break;
+
+ /* Other types should not be seen here. */
+ default:
+ return NULL;
+ }
+
+ p = d_make_empty (di);
+ if (p != NULL)
+ {
+ p->type = type;
+ p->u.s_binary.left = left;
+ p->u.s_binary.right = right;
+ }
+ return p;
+}
+
+/* Add a new demangle mangled name component. */
+
+static struct demangle_component *
+d_make_demangle_mangled_name (struct d_info *di, const char *s)
+{
+ if (d_peek_char (di) != '_' || d_peek_next_char (di) != 'Z')
+ return d_make_name (di, s, strlen (s));
+ d_advance (di, 2);
+ return d_encoding (di, 0);
+}
+
+/* Add a new name component. */
+
+static struct demangle_component *
+d_make_name (struct d_info *di, const char *s, int len)
+{
+ struct demangle_component *p;
+
+ p = d_make_empty (di);
+ if (! cplus_demangle_fill_name (p, s, len))
+ return NULL;
+ return p;
+}
+
+/* Add a new builtin type component. */
+
+static struct demangle_component *
+d_make_builtin_type (struct d_info *di,
+ const struct demangle_builtin_type_info *type)
+{
+ struct demangle_component *p;
+
+ if (type == NULL)
+ return NULL;
+ p = d_make_empty (di);
+ if (p != NULL)
+ {
+ p->type = DEMANGLE_COMPONENT_BUILTIN_TYPE;
+ p->u.s_builtin.type = type;
+ }
+ return p;
+}
+
+/* Add a new operator component. */
+
+static struct demangle_component *
+d_make_operator (struct d_info *di, const struct demangle_operator_info *op)
+{
+ struct demangle_component *p;
+
+ p = d_make_empty (di);
+ if (p != NULL)
+ {
+ p->type = DEMANGLE_COMPONENT_OPERATOR;
+ p->u.s_operator.op = op;
+ }
+ return p;
+}
+
+/* Add a new extended operator component. */
+
+static struct demangle_component *
+d_make_extended_operator (struct d_info *di, int args,
+ struct demangle_component *name)
+{
+ struct demangle_component *p;
+
+ p = d_make_empty (di);
+ if (! cplus_demangle_fill_extended_operator (p, args, name))
+ return NULL;
+ return p;
+}
+
+static struct demangle_component *
+d_make_default_arg (struct d_info *di, int num,
+ struct demangle_component *sub)
+{
+ struct demangle_component *p = d_make_empty (di);
+ if (p)
+ {
+ p->type = DEMANGLE_COMPONENT_DEFAULT_ARG;
+ p->u.s_unary_num.num = num;
+ p->u.s_unary_num.sub = sub;
+ }
+ return p;
+}
+
+/* Add a new constructor component. */
+
+static struct demangle_component *
+d_make_ctor (struct d_info *di, enum gnu_v3_ctor_kinds kind,
+ struct demangle_component *name)
+{
+ struct demangle_component *p;
+
+ p = d_make_empty (di);
+ if (! cplus_demangle_fill_ctor (p, kind, name))
+ return NULL;
+ return p;
+}
+
+/* Add a new destructor component. */
+
+static struct demangle_component *
+d_make_dtor (struct d_info *di, enum gnu_v3_dtor_kinds kind,
+ struct demangle_component *name)
+{
+ struct demangle_component *p;
+
+ p = d_make_empty (di);
+ if (! cplus_demangle_fill_dtor (p, kind, name))
+ return NULL;
+ return p;
+}
+
+/* Add a new template parameter. */
+
+static struct demangle_component *
+d_make_template_param (struct d_info *di, long i)
+{
+ struct demangle_component *p;
+
+ p = d_make_empty (di);
+ if (p != NULL)
+ {
+ p->type = DEMANGLE_COMPONENT_TEMPLATE_PARAM;
+ p->u.s_number.number = i;
+ }
+ return p;
+}
+
+/* Add a new function parameter. */
+
+static struct demangle_component *
+d_make_function_param (struct d_info *di, long i)
+{
+ struct demangle_component *p;
+
+ p = d_make_empty (di);
+ if (p != NULL)
+ {
+ p->type = DEMANGLE_COMPONENT_FUNCTION_PARAM;
+ p->u.s_number.number = i;
+ }
+ return p;
+}
+
+/* Add a new standard substitution component. */
+
+static struct demangle_component *
+d_make_sub (struct d_info *di, const char *name, int len)
+{
+ struct demangle_component *p;
+
+ p = d_make_empty (di);
+ if (p != NULL)
+ {
+ p->type = DEMANGLE_COMPONENT_SUB_STD;
+ p->u.s_string.string = name;
+ p->u.s_string.len = len;
+ }
+ return p;
+}
+
+/* <mangled-name> ::= _Z <encoding> [<clone-suffix>]*
+
+ TOP_LEVEL is non-zero when called at the top level. */
+
+CP_STATIC_IF_GLIBCPP_V3
+struct demangle_component *
+cplus_demangle_mangled_name (struct d_info *di, int top_level)
+{
+ struct demangle_component *p;
+
+ if (! d_check_char (di, '_')
+ /* Allow missing _ if not at toplevel to work around a
+ bug in G++ abi-version=2 mangling; see the comment in
+ write_template_arg. */
+ && top_level)
+ return NULL;
+ if (! d_check_char (di, 'Z'))
+ return NULL;
+ p = d_encoding (di, top_level);
+
+ /* If at top level and parsing parameters, check for a clone
+ suffix. */
+ if (top_level && (di->options & DMGL_PARAMS) != 0)
+ while (d_peek_char (di) == '.'
+ && (IS_LOWER (d_peek_next_char (di))
+ || d_peek_next_char (di) == '_'
+ || IS_DIGIT (d_peek_next_char (di))))
+ p = d_clone_suffix (di, p);
+
+ return p;
+}
+
+/* Return whether a function should have a return type. The argument
+ is the function name, which may be qualified in various ways. The
+ rules are that template functions have return types with some
+ exceptions, function types which are not part of a function name
+ mangling have return types with some exceptions, and non-template
+ function names do not have return types. The exceptions are that
+ constructors, destructors, and conversion operators do not have
+ return types. */
+
+static int
+has_return_type (struct demangle_component *dc)
+{
+ if (dc == NULL)
+ return 0;
+ switch (dc->type)
+ {
+ default:
+ return 0;
+ case DEMANGLE_COMPONENT_TEMPLATE:
+ return ! is_ctor_dtor_or_conversion (d_left (dc));
+ case DEMANGLE_COMPONENT_RESTRICT_THIS:
+ case DEMANGLE_COMPONENT_VOLATILE_THIS:
+ case DEMANGLE_COMPONENT_CONST_THIS:
+ case DEMANGLE_COMPONENT_REFERENCE_THIS:
+ case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS:
+ return has_return_type (d_left (dc));
+ }
+}
+
+/* Return whether a name is a constructor, a destructor, or a
+ conversion operator. */
+
+static int
+is_ctor_dtor_or_conversion (struct demangle_component *dc)
+{
+ if (dc == NULL)
+ return 0;
+ switch (dc->type)
+ {
+ default:
+ return 0;
+ case DEMANGLE_COMPONENT_QUAL_NAME:
+ case DEMANGLE_COMPONENT_LOCAL_NAME:
+ return is_ctor_dtor_or_conversion (d_right (dc));
+ case DEMANGLE_COMPONENT_CTOR:
+ case DEMANGLE_COMPONENT_DTOR:
+ case DEMANGLE_COMPONENT_CAST:
+ return 1;
+ }
+}
+
+/* <encoding> ::= <(function) name> <bare-function-type>
+ ::= <(data) name>
+ ::= <special-name>
+
+ TOP_LEVEL is non-zero when called at the top level, in which case
+ if DMGL_PARAMS is not set we do not demangle the function
+ parameters. We only set this at the top level, because otherwise
+ we would not correctly demangle names in local scopes. */
+
+static struct demangle_component *
+d_encoding (struct d_info *di, int top_level)
+{
+ char peek = d_peek_char (di);
+
+ if (peek == 'G' || peek == 'T')
+ return d_special_name (di);
+ else
+ {
+ struct demangle_component *dc;
+
+ dc = d_name (di);
+
+ if (dc != NULL && top_level && (di->options & DMGL_PARAMS) == 0)
+ {
+ /* Strip off any initial CV-qualifiers, as they really apply
+ to the `this' parameter, and they were not output by the
+ v2 demangler without DMGL_PARAMS. */
+ while (dc->type == DEMANGLE_COMPONENT_RESTRICT_THIS
+ || dc->type == DEMANGLE_COMPONENT_VOLATILE_THIS
+ || dc->type == DEMANGLE_COMPONENT_CONST_THIS
+ || dc->type == DEMANGLE_COMPONENT_REFERENCE_THIS
+ || dc->type == DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS)
+ dc = d_left (dc);
+
+ /* If the top level is a DEMANGLE_COMPONENT_LOCAL_NAME, then
+ there may be CV-qualifiers on its right argument which
+ really apply here; this happens when parsing a class
+ which is local to a function. */
+ if (dc->type == DEMANGLE_COMPONENT_LOCAL_NAME)
+ {
+ struct demangle_component *dcr;
+
+ dcr = d_right (dc);
+ while (dcr->type == DEMANGLE_COMPONENT_RESTRICT_THIS
+ || dcr->type == DEMANGLE_COMPONENT_VOLATILE_THIS
+ || dcr->type == DEMANGLE_COMPONENT_CONST_THIS
+ || dcr->type == DEMANGLE_COMPONENT_REFERENCE_THIS
+ || dcr->type == DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS)
+ dcr = d_left (dcr);
+ dc->u.s_binary.right = dcr;
+ }
+
+ return dc;
+ }
+
+ peek = d_peek_char (di);
+ if (dc == NULL || peek == '\0' || peek == 'E')
+ return dc;
+ return d_make_comp (di, DEMANGLE_COMPONENT_TYPED_NAME, dc,
+ d_bare_function_type (di, has_return_type (dc)));
+ }
+}
+
+/* <tagged-name> ::= <name> B <source-name> */
+
+static struct demangle_component *
+d_abi_tags (struct d_info *di, struct demangle_component *dc)
+{
+ char peek;
+ while (peek = d_peek_char (di),
+ peek == 'B')
+ {
+ struct demangle_component *tag;
+ d_advance (di, 1);
+ tag = d_source_name (di);
+ dc = d_make_comp (di, DEMANGLE_COMPONENT_TAGGED_NAME, dc, tag);
+ }
+ return dc;
+}
+
+/* <name> ::= <nested-name>
+ ::= <unscoped-name>
+ ::= <unscoped-template-name> <template-args>
+ ::= <local-name>
+
+ <unscoped-name> ::= <unqualified-name>
+ ::= St <unqualified-name>
+
+ <unscoped-template-name> ::= <unscoped-name>
+ ::= <substitution>
+*/
+
+static struct demangle_component *
+d_name (struct d_info *di)
+{
+ char peek = d_peek_char (di);
+ struct demangle_component *dc;
+
+ switch (peek)
+ {
+ case 'N':
+ return d_nested_name (di);
+
+ case 'Z':
+ return d_local_name (di);
+
+ case 'U':
+ return d_unqualified_name (di);
+
+ case 'S':
+ {
+ int subst;
+
+ if (d_peek_next_char (di) != 't')
+ {
+ dc = d_substitution (di, 0);
+ subst = 1;
+ }
+ else
+ {
+ d_advance (di, 2);
+ dc = d_make_comp (di, DEMANGLE_COMPONENT_QUAL_NAME,
+ d_make_name (di, "std", 3),
+ d_unqualified_name (di));
+ di->expansion += 3;
+ subst = 0;
+ }
+
+ if (d_peek_char (di) != 'I')
+ {
+ /* The grammar does not permit this case to occur if we
+ called d_substitution() above (i.e., subst == 1). We
+ don't bother to check. */
+ }
+ else
+ {
+ /* This is <template-args>, which means that we just saw
+ <unscoped-template-name>, which is a substitution
+ candidate if we didn't just get it from a
+ substitution. */
+ if (! subst)
+ {
+ if (! d_add_substitution (di, dc))
+ return NULL;
+ }
+ dc = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, dc,
+ d_template_args (di));
+ }
+
+ return dc;
+ }
+
+ case 'L':
+ default:
+ dc = d_unqualified_name (di);
+ if (d_peek_char (di) == 'I')
+ {
+ /* This is <template-args>, which means that we just saw
+ <unscoped-template-name>, which is a substitution
+ candidate. */
+ if (! d_add_substitution (di, dc))
+ return NULL;
+ dc = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, dc,
+ d_template_args (di));
+ }
+ return dc;
+ }
+}
+
+/* <nested-name> ::= N [<CV-qualifiers>] [<ref-qualifier>] <prefix> <unqualified-name> E
+ ::= N [<CV-qualifiers>] [<ref-qualifier>] <template-prefix> <template-args> E
+*/
+
+static struct demangle_component *
+d_nested_name (struct d_info *di)
+{
+ struct demangle_component *ret;
+ struct demangle_component **pret;
+ struct demangle_component *rqual;
+
+ if (! d_check_char (di, 'N'))
+ return NULL;
+
+ pret = d_cv_qualifiers (di, &ret, 1);
+ if (pret == NULL)
+ return NULL;
+
+ /* Parse the ref-qualifier now and then attach it
+ once we have something to attach it to. */
+ rqual = d_ref_qualifier (di, NULL);
+
+ *pret = d_prefix (di);
+ if (*pret == NULL)
+ return NULL;
+
+ if (rqual)
+ {
+ d_left (rqual) = ret;
+ ret = rqual;
+ }
+
+ if (! d_check_char (di, 'E'))
+ return NULL;
+
+ return ret;
+}
+
+/* <prefix> ::= <prefix> <unqualified-name>
+ ::= <template-prefix> <template-args>
+ ::= <template-param>
+ ::= <decltype>
+ ::=
+ ::= <substitution>
+
+ <template-prefix> ::= <prefix> <(template) unqualified-name>
+ ::= <template-param>
+ ::= <substitution>
+*/
+
+static struct demangle_component *
+d_prefix (struct d_info *di)
+{
+ struct demangle_component *ret = NULL;
+
+ while (1)
+ {
+ char peek;
+ enum demangle_component_type comb_type;
+ struct demangle_component *dc;
+
+ peek = d_peek_char (di);
+ if (peek == '\0')
+ return NULL;
+
+ /* The older code accepts a <local-name> here, but I don't see
+ that in the grammar. The older code does not accept a
+ <template-param> here. */
+
+ comb_type = DEMANGLE_COMPONENT_QUAL_NAME;
+ if (peek == 'D')
+ {
+ char peek2 = d_peek_next_char (di);
+ if (peek2 == 'T' || peek2 == 't')
+ /* Decltype. */
+ dc = cplus_demangle_type (di);
+ else
+ /* Destructor name. */
+ dc = d_unqualified_name (di);
+ }
+ else if (IS_DIGIT (peek)
+ || IS_LOWER (peek)
+ || peek == 'C'
+ || peek == 'U'
+ || peek == 'L')
+ dc = d_unqualified_name (di);
+ else if (peek == 'S')
+ dc = d_substitution (di, 1);
+ else if (peek == 'I')
+ {
+ if (ret == NULL)
+ return NULL;
+ comb_type = DEMANGLE_COMPONENT_TEMPLATE;
+ dc = d_template_args (di);
+ }
+ else if (peek == 'T')
+ dc = d_template_param (di);
+ else if (peek == 'E')
+ return ret;
+ else if (peek == 'M')
+ {
+ /* Initializer scope for a lambda. We don't need to represent
+ this; the normal code will just treat the variable as a type
+ scope, which gives appropriate output. */
+ if (ret == NULL)
+ return NULL;
+ d_advance (di, 1);
+ continue;
+ }
+ else
+ return NULL;
+
+ if (ret == NULL)
+ ret = dc;
+ else
+ ret = d_make_comp (di, comb_type, ret, dc);
+
+ if (peek != 'S' && d_peek_char (di) != 'E')
+ {
+ if (! d_add_substitution (di, ret))
+ return NULL;
+ }
+ }
+}
+
+/* <unqualified-name> ::= <operator-name>
+ ::= <ctor-dtor-name>
+ ::= <source-name>
+ ::= <local-source-name>
+
+ <local-source-name> ::= L <source-name> <discriminator>
+*/
+
+static struct demangle_component *
+d_unqualified_name (struct d_info *di)
+{
+ struct demangle_component *ret;
+ char peek;
+
+ peek = d_peek_char (di);
+ if (IS_DIGIT (peek))
+ ret = d_source_name (di);
+ else if (IS_LOWER (peek))
+ {
+ ret = d_operator_name (di);
+ if (ret != NULL && ret->type == DEMANGLE_COMPONENT_OPERATOR)
+ {
+ di->expansion += sizeof "operator" + ret->u.s_operator.op->len - 2;
+ if (!strcmp (ret->u.s_operator.op->code, "li"))
+ ret = d_make_comp (di, DEMANGLE_COMPONENT_UNARY, ret,
+ d_source_name (di));
+ }
+ }
+ else if (peek == 'C' || peek == 'D')
+ ret = d_ctor_dtor_name (di);
+ else if (peek == 'L')
+ {
+ d_advance (di, 1);
+
+ ret = d_source_name (di);
+ if (ret == NULL)
+ return NULL;
+ if (! d_discriminator (di))
+ return NULL;
+ }
+ else if (peek == 'U')
+ {
+ switch (d_peek_next_char (di))
+ {
+ case 'l':
+ ret = d_lambda (di);
+ break;
+ case 't':
+ ret = d_unnamed_type (di);
+ break;
+ default:
+ return NULL;
+ }
+ }
+ else
+ return NULL;
+
+ if (d_peek_char (di) == 'B')
+ ret = d_abi_tags (di, ret);
+ return ret;
+}
+
+/* <source-name> ::= <(positive length) number> <identifier> */
+
+static struct demangle_component *
+d_source_name (struct d_info *di)
+{
+ long len;
+ struct demangle_component *ret;
+
+ len = d_number (di);
+ if (len <= 0)
+ return NULL;
+ ret = d_identifier (di, len);
+ di->last_name = ret;
+ return ret;
+}
+
+/* number ::= [n] <(non-negative decimal integer)> */
+
+static long
+d_number (struct d_info *di)
+{
+ int negative;
+ char peek;
+ long ret;
+
+ negative = 0;
+ peek = d_peek_char (di);
+ if (peek == 'n')
+ {
+ negative = 1;
+ d_advance (di, 1);
+ peek = d_peek_char (di);
+ }
+
+ ret = 0;
+ while (1)
+ {
+ if (! IS_DIGIT (peek))
+ {
+ if (negative)
+ ret = - ret;
+ return ret;
+ }
+ ret = ret * 10 + peek - '0';
+ d_advance (di, 1);
+ peek = d_peek_char (di);
+ }
+}
+
+/* Like d_number, but returns a demangle_component. */
+
+static struct demangle_component *
+d_number_component (struct d_info *di)
+{
+ struct demangle_component *ret = d_make_empty (di);
+ if (ret)
+ {
+ ret->type = DEMANGLE_COMPONENT_NUMBER;
+ ret->u.s_number.number = d_number (di);
+ }
+ return ret;
+}
+
+/* identifier ::= <(unqualified source code identifier)> */
+
+static struct demangle_component *
+d_identifier (struct d_info *di, int len)
+{
+ const char *name;
+
+ name = d_str (di);
+
+ if (di->send - name < len)
+ return NULL;
+
+ d_advance (di, len);
+
+ /* A Java mangled name may have a trailing '$' if it is a C++
+ keyword. This '$' is not included in the length count. We just
+ ignore the '$'. */
+ if ((di->options & DMGL_JAVA) != 0
+ && d_peek_char (di) == '$')
+ d_advance (di, 1);
+
+ /* Look for something which looks like a gcc encoding of an
+ anonymous namespace, and replace it with a more user friendly
+ name. */
+ if (len >= (int) ANONYMOUS_NAMESPACE_PREFIX_LEN + 2
+ && memcmp (name, ANONYMOUS_NAMESPACE_PREFIX,
+ ANONYMOUS_NAMESPACE_PREFIX_LEN) == 0)
+ {
+ const char *s;
+
+ s = name + ANONYMOUS_NAMESPACE_PREFIX_LEN;
+ if ((*s == '.' || *s == '_' || *s == '$')
+ && s[1] == 'N')
+ {
+ di->expansion -= len - sizeof "(anonymous namespace)";
+ return d_make_name (di, "(anonymous namespace)",
+ sizeof "(anonymous namespace)" - 1);
+ }
+ }
+
+ return d_make_name (di, name, len);
+}
+
+/* operator_name ::= many different two character encodings.
+ ::= cv <type>
+ ::= v <digit> <source-name>
+
+ This list is sorted for binary search. */
+
+#define NL(s) s, (sizeof s) - 1
+
+CP_STATIC_IF_GLIBCPP_V3
+const struct demangle_operator_info cplus_demangle_operators[] =
+{
+ { "aN", NL ("&="), 2 },
+ { "aS", NL ("="), 2 },
+ { "aa", NL ("&&"), 2 },
+ { "ad", NL ("&"), 1 },
+ { "an", NL ("&"), 2 },
+ { "at", NL ("alignof "), 1 },
+ { "az", NL ("alignof "), 1 },
+ { "cc", NL ("const_cast"), 2 },
+ { "cl", NL ("()"), 2 },
+ { "cm", NL (","), 2 },
+ { "co", NL ("~"), 1 },
+ { "dV", NL ("/="), 2 },
+ { "da", NL ("delete[] "), 1 },
+ { "dc", NL ("dynamic_cast"), 2 },
+ { "de", NL ("*"), 1 },
+ { "dl", NL ("delete "), 1 },
+ { "ds", NL (".*"), 2 },
+ { "dt", NL ("."), 2 },
+ { "dv", NL ("/"), 2 },
+ { "eO", NL ("^="), 2 },
+ { "eo", NL ("^"), 2 },
+ { "eq", NL ("=="), 2 },
+ { "ge", NL (">="), 2 },
+ { "gs", NL ("::"), 1 },
+ { "gt", NL (">"), 2 },
+ { "ix", NL ("[]"), 2 },
+ { "lS", NL ("<<="), 2 },
+ { "le", NL ("<="), 2 },
+ { "li", NL ("operator\"\" "), 1 },
+ { "ls", NL ("<<"), 2 },
+ { "lt", NL ("<"), 2 },
+ { "mI", NL ("-="), 2 },
+ { "mL", NL ("*="), 2 },
+ { "mi", NL ("-"), 2 },
+ { "ml", NL ("*"), 2 },
+ { "mm", NL ("--"), 1 },
+ { "na", NL ("new[]"), 3 },
+ { "ne", NL ("!="), 2 },
+ { "ng", NL ("-"), 1 },
+ { "nt", NL ("!"), 1 },
+ { "nw", NL ("new"), 3 },
+ { "oR", NL ("|="), 2 },
+ { "oo", NL ("||"), 2 },
+ { "or", NL ("|"), 2 },
+ { "pL", NL ("+="), 2 },
+ { "pl", NL ("+"), 2 },
+ { "pm", NL ("->*"), 2 },
+ { "pp", NL ("++"), 1 },
+ { "ps", NL ("+"), 1 },
+ { "pt", NL ("->"), 2 },
+ { "qu", NL ("?"), 3 },
+ { "rM", NL ("%="), 2 },
+ { "rS", NL (">>="), 2 },
+ { "rc", NL ("reinterpret_cast"), 2 },
+ { "rm", NL ("%"), 2 },
+ { "rs", NL (">>"), 2 },
+ { "sc", NL ("static_cast"), 2 },
+ { "st", NL ("sizeof "), 1 },
+ { "sz", NL ("sizeof "), 1 },
+ { "tr", NL ("throw"), 0 },
+ { "tw", NL ("throw "), 1 },
+ { NULL, NULL, 0, 0 }
+};
+
+static struct demangle_component *
+d_operator_name (struct d_info *di)
+{
+ char c1;
+ char c2;
+
+ c1 = d_next_char (di);
+ c2 = d_next_char (di);
+ if (c1 == 'v' && IS_DIGIT (c2))
+ return d_make_extended_operator (di, c2 - '0', d_source_name (di));
+ else if (c1 == 'c' && c2 == 'v')
+ {
+ struct demangle_component *type;
+ int was_conversion = di->is_conversion;
+
+ di->is_conversion = ! di->is_expression;
+ type = cplus_demangle_type (di);
+ di->is_conversion = was_conversion;
+ return d_make_comp (di, DEMANGLE_COMPONENT_CAST, type, NULL);
+ }
+ else
+ {
+ /* LOW is the inclusive lower bound. */
+ int low = 0;
+ /* HIGH is the exclusive upper bound. We subtract one to ignore
+ the sentinel at the end of the array. */
+ int high = ((sizeof (cplus_demangle_operators)
+ / sizeof (cplus_demangle_operators[0]))
+ - 1);
+
+ while (1)
+ {
+ int i;
+ const struct demangle_operator_info *p;
+
+ i = low + (high - low) / 2;
+ p = cplus_demangle_operators + i;
+
+ if (c1 == p->code[0] && c2 == p->code[1])
+ return d_make_operator (di, p);
+
+ if (c1 < p->code[0] || (c1 == p->code[0] && c2 < p->code[1]))
+ high = i;
+ else
+ low = i + 1;
+ if (low == high)
+ return NULL;
+ }
+ }
+}
+
+static struct demangle_component *
+d_make_character (struct d_info *di, int c)
+{
+ struct demangle_component *p;
+ p = d_make_empty (di);
+ if (p != NULL)
+ {
+ p->type = DEMANGLE_COMPONENT_CHARACTER;
+ p->u.s_character.character = c;
+ }
+ return p;
+}
+
+static struct demangle_component *
+d_java_resource (struct d_info *di)
+{
+ struct demangle_component *p = NULL;
+ struct demangle_component *next = NULL;
+ long len, i;
+ char c;
+ const char *str;
+
+ len = d_number (di);
+ if (len <= 1)
+ return NULL;
+
+ /* Eat the leading '_'. */
+ if (d_next_char (di) != '_')
+ return NULL;
+ len--;
+
+ str = d_str (di);
+ i = 0;
+
+ while (len > 0)
+ {
+ c = str[i];
+ if (!c)
+ return NULL;
+
+ /* Each chunk is either a '$' escape... */
+ if (c == '$')
+ {
+ i++;
+ switch (str[i++])
+ {
+ case 'S':
+ c = '/';
+ break;
+ case '_':
+ c = '.';
+ break;
+ case '$':
+ c = '$';
+ break;
+ default:
+ return NULL;
+ }
+ next = d_make_character (di, c);
+ d_advance (di, i);
+ str = d_str (di);
+ len -= i;
+ i = 0;
+ if (next == NULL)
+ return NULL;
+ }
+ /* ... or a sequence of characters. */
+ else
+ {
+ while (i < len && str[i] && str[i] != '$')
+ i++;
+
+ next = d_make_name (di, str, i);
+ d_advance (di, i);
+ str = d_str (di);
+ len -= i;
+ i = 0;
+ if (next == NULL)
+ return NULL;
+ }
+
+ if (p == NULL)
+ p = next;
+ else
+ {
+ p = d_make_comp (di, DEMANGLE_COMPONENT_COMPOUND_NAME, p, next);
+ if (p == NULL)
+ return NULL;
+ }
+ }
+
+ p = d_make_comp (di, DEMANGLE_COMPONENT_JAVA_RESOURCE, p, NULL);
+
+ return p;
+}
+
+/* <special-name> ::= TV <type>
+ ::= TT <type>
+ ::= TI <type>
+ ::= TS <type>
+ ::= GV <(object) name>
+ ::= T <call-offset> <(base) encoding>
+ ::= Tc <call-offset> <call-offset> <(base) encoding>
+ Also g++ extensions:
+ ::= TC <type> <(offset) number> _ <(base) type>
+ ::= TF <type>
+ ::= TJ <type>
+ ::= GR <name>
+ ::= GA <encoding>
+ ::= Gr <resource name>
+ ::= GTt <encoding>
+ ::= GTn <encoding>
+*/
+
+static struct demangle_component *
+d_special_name (struct d_info *di)
+{
+ di->expansion += 20;
+ if (d_check_char (di, 'T'))
+ {
+ switch (d_next_char (di))
+ {
+ case 'V':
+ di->expansion -= 5;
+ return d_make_comp (di, DEMANGLE_COMPONENT_VTABLE,
+ cplus_demangle_type (di), NULL);
+ case 'T':
+ di->expansion -= 10;
+ return d_make_comp (di, DEMANGLE_COMPONENT_VTT,
+ cplus_demangle_type (di), NULL);
+ case 'I':
+ return d_make_comp (di, DEMANGLE_COMPONENT_TYPEINFO,
+ cplus_demangle_type (di), NULL);
+ case 'S':
+ return d_make_comp (di, DEMANGLE_COMPONENT_TYPEINFO_NAME,
+ cplus_demangle_type (di), NULL);
+
+ case 'h':
+ if (! d_call_offset (di, 'h'))
+ return NULL;
+ return d_make_comp (di, DEMANGLE_COMPONENT_THUNK,
+ d_encoding (di, 0), NULL);
+
+ case 'v':
+ if (! d_call_offset (di, 'v'))
+ return NULL;
+ return d_make_comp (di, DEMANGLE_COMPONENT_VIRTUAL_THUNK,
+ d_encoding (di, 0), NULL);
+
+ case 'c':
+ if (! d_call_offset (di, '\0'))
+ return NULL;
+ if (! d_call_offset (di, '\0'))
+ return NULL;
+ return d_make_comp (di, DEMANGLE_COMPONENT_COVARIANT_THUNK,
+ d_encoding (di, 0), NULL);
+
+ case 'C':
+ {
+ struct demangle_component *derived_type;
+ long offset;
+ struct demangle_component *base_type;
+
+ derived_type = cplus_demangle_type (di);
+ offset = d_number (di);
+ if (offset < 0)
+ return NULL;
+ if (! d_check_char (di, '_'))
+ return NULL;
+ base_type = cplus_demangle_type (di);
+ /* We don't display the offset. FIXME: We should display
+ it in verbose mode. */
+ di->expansion += 5;
+ return d_make_comp (di, DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE,
+ base_type, derived_type);
+ }
+
+ case 'F':
+ return d_make_comp (di, DEMANGLE_COMPONENT_TYPEINFO_FN,
+ cplus_demangle_type (di), NULL);
+ case 'J':
+ return d_make_comp (di, DEMANGLE_COMPONENT_JAVA_CLASS,
+ cplus_demangle_type (di), NULL);
+
+ case 'H':
+ return d_make_comp (di, DEMANGLE_COMPONENT_TLS_INIT,
+ d_name (di), NULL);
+
+ case 'W':
+ return d_make_comp (di, DEMANGLE_COMPONENT_TLS_WRAPPER,
+ d_name (di), NULL);
+
+ default:
+ return NULL;
+ }
+ }
+ else if (d_check_char (di, 'G'))
+ {
+ switch (d_next_char (di))
+ {
+ case 'V':
+ return d_make_comp (di, DEMANGLE_COMPONENT_GUARD, d_name (di), NULL);
+
+ case 'R':
+ {
+ struct demangle_component *name = d_name (di);
+ return d_make_comp (di, DEMANGLE_COMPONENT_REFTEMP, name,
+ d_number_component (di));
+ }
+
+ case 'A':
+ return d_make_comp (di, DEMANGLE_COMPONENT_HIDDEN_ALIAS,
+ d_encoding (di, 0), NULL);
+
+ case 'T':
+ switch (d_next_char (di))
+ {
+ case 'n':
+ return d_make_comp (di, DEMANGLE_COMPONENT_NONTRANSACTION_CLONE,
+ d_encoding (di, 0), NULL);
+ default:
+ /* ??? The proposal is that other letters (such as 'h') stand
+ for different variants of transaction cloning, such as
+ compiling directly for hardware transaction support. But
+ they still should all be transactional clones of some sort
+ so go ahead and call them that. */
+ case 't':
+ return d_make_comp (di, DEMANGLE_COMPONENT_TRANSACTION_CLONE,
+ d_encoding (di, 0), NULL);
+ }
+
+ case 'r':
+ return d_java_resource (di);
+
+ default:
+ return NULL;
+ }
+ }
+ else
+ return NULL;
+}
+
+/* <call-offset> ::= h <nv-offset> _
+ ::= v <v-offset> _
+
+ <nv-offset> ::= <(offset) number>
+
+ <v-offset> ::= <(offset) number> _ <(virtual offset) number>
+
+ The C parameter, if not '\0', is a character we just read which is
+ the start of the <call-offset>.
+
+ We don't display the offset information anywhere. FIXME: We should
+ display it in verbose mode. */
+
+static int
+d_call_offset (struct d_info *di, int c)
+{
+ if (c == '\0')
+ c = d_next_char (di);
+
+ if (c == 'h')
+ d_number (di);
+ else if (c == 'v')
+ {
+ d_number (di);
+ if (! d_check_char (di, '_'))
+ return 0;
+ d_number (di);
+ }
+ else
+ return 0;
+
+ if (! d_check_char (di, '_'))
+ return 0;
+
+ return 1;
+}
+
+/* <ctor-dtor-name> ::= C1
+ ::= C2
+ ::= C3
+ ::= D0
+ ::= D1
+ ::= D2
+*/
+
+static struct demangle_component *
+d_ctor_dtor_name (struct d_info *di)
+{
+ if (di->last_name != NULL)
+ {
+ if (di->last_name->type == DEMANGLE_COMPONENT_NAME)
+ di->expansion += di->last_name->u.s_name.len;
+ else if (di->last_name->type == DEMANGLE_COMPONENT_SUB_STD)
+ di->expansion += di->last_name->u.s_string.len;
+ }
+ switch (d_peek_char (di))
+ {
+ case 'C':
+ {
+ enum gnu_v3_ctor_kinds kind;
+
+ switch (d_peek_next_char (di))
+ {
+ case '1':
+ kind = gnu_v3_complete_object_ctor;
+ break;
+ case '2':
+ kind = gnu_v3_base_object_ctor;
+ break;
+ case '3':
+ kind = gnu_v3_complete_object_allocating_ctor;
+ break;
+ case '4':
+ kind = gnu_v3_unified_ctor;
+ break;
+ case '5':
+ kind = gnu_v3_object_ctor_group;
+ break;
+ default:
+ return NULL;
+ }
+ d_advance (di, 2);
+ return d_make_ctor (di, kind, di->last_name);
+ }
+
+ case 'D':
+ {
+ enum gnu_v3_dtor_kinds kind;
+
+ switch (d_peek_next_char (di))
+ {
+ case '0':
+ kind = gnu_v3_deleting_dtor;
+ break;
+ case '1':
+ kind = gnu_v3_complete_object_dtor;
+ break;
+ case '2':
+ kind = gnu_v3_base_object_dtor;
+ break;
+ /* digit '3' is not used */
+ case '4':
+ kind = gnu_v3_unified_dtor;
+ break;
+ case '5':
+ kind = gnu_v3_object_dtor_group;
+ break;
+ default:
+ return NULL;
+ }
+ d_advance (di, 2);
+ return d_make_dtor (di, kind, di->last_name);
+ }
+
+ default:
+ return NULL;
+ }
+}
+
+/* <type> ::= <builtin-type>
+ ::= <function-type>
+ ::= <class-enum-type>
+ ::= <array-type>
+ ::= <pointer-to-member-type>
+ ::= <template-param>
+ ::= <template-template-param> <template-args>
+ ::= <substitution>
+ ::= <CV-qualifiers> <type>
+ ::= P <type>
+ ::= R <type>
+ ::= O <type> (C++0x)
+ ::= C <type>
+ ::= G <type>
+ ::= U <source-name> <type>
+
+ <builtin-type> ::= various one letter codes
+ ::= u <source-name>
+*/
+
+CP_STATIC_IF_GLIBCPP_V3
+const struct demangle_builtin_type_info
+cplus_demangle_builtin_types[D_BUILTIN_TYPE_COUNT] =
+{
+ /* a */ { NL ("signed char"), NL ("signed char"), D_PRINT_DEFAULT },
+ /* b */ { NL ("bool"), NL ("boolean"), D_PRINT_BOOL },
+ /* c */ { NL ("char"), NL ("byte"), D_PRINT_DEFAULT },
+ /* d */ { NL ("double"), NL ("double"), D_PRINT_FLOAT },
+ /* e */ { NL ("long double"), NL ("long double"), D_PRINT_FLOAT },
+ /* f */ { NL ("float"), NL ("float"), D_PRINT_FLOAT },
+ /* g */ { NL ("__float128"), NL ("__float128"), D_PRINT_FLOAT },
+ /* h */ { NL ("unsigned char"), NL ("unsigned char"), D_PRINT_DEFAULT },
+ /* i */ { NL ("int"), NL ("int"), D_PRINT_INT },
+ /* j */ { NL ("unsigned int"), NL ("unsigned"), D_PRINT_UNSIGNED },
+ /* k */ { NULL, 0, NULL, 0, D_PRINT_DEFAULT },
+ /* l */ { NL ("long"), NL ("long"), D_PRINT_LONG },
+ /* m */ { NL ("unsigned long"), NL ("unsigned long"), D_PRINT_UNSIGNED_LONG },
+ /* n */ { NL ("__int128"), NL ("__int128"), D_PRINT_DEFAULT },
+ /* o */ { NL ("unsigned __int128"), NL ("unsigned __int128"),
+ D_PRINT_DEFAULT },
+ /* p */ { NULL, 0, NULL, 0, D_PRINT_DEFAULT },
+ /* q */ { NULL, 0, NULL, 0, D_PRINT_DEFAULT },
+ /* r */ { NULL, 0, NULL, 0, D_PRINT_DEFAULT },
+ /* s */ { NL ("short"), NL ("short"), D_PRINT_DEFAULT },
+ /* t */ { NL ("unsigned short"), NL ("unsigned short"), D_PRINT_DEFAULT },
+ /* u */ { NULL, 0, NULL, 0, D_PRINT_DEFAULT },
+ /* v */ { NL ("void"), NL ("void"), D_PRINT_VOID },
+ /* w */ { NL ("wchar_t"), NL ("char"), D_PRINT_DEFAULT },
+ /* x */ { NL ("long long"), NL ("long"), D_PRINT_LONG_LONG },
+ /* y */ { NL ("unsigned long long"), NL ("unsigned long long"),
+ D_PRINT_UNSIGNED_LONG_LONG },
+ /* z */ { NL ("..."), NL ("..."), D_PRINT_DEFAULT },
+ /* 26 */ { NL ("decimal32"), NL ("decimal32"), D_PRINT_DEFAULT },
+ /* 27 */ { NL ("decimal64"), NL ("decimal64"), D_PRINT_DEFAULT },
+ /* 28 */ { NL ("decimal128"), NL ("decimal128"), D_PRINT_DEFAULT },
+ /* 29 */ { NL ("half"), NL ("half"), D_PRINT_FLOAT },
+ /* 30 */ { NL ("char16_t"), NL ("char16_t"), D_PRINT_DEFAULT },
+ /* 31 */ { NL ("char32_t"), NL ("char32_t"), D_PRINT_DEFAULT },
+ /* 32 */ { NL ("decltype(nullptr)"), NL ("decltype(nullptr)"),
+ D_PRINT_DEFAULT },
+};
+
+CP_STATIC_IF_GLIBCPP_V3
+struct demangle_component *
+cplus_demangle_type (struct d_info *di)
+{
+ char peek;
+ struct demangle_component *ret;
+ int can_subst;
+
+ /* The ABI specifies that when CV-qualifiers are used, the base type
+ is substitutable, and the fully qualified type is substitutable,
+ but the base type with a strict subset of the CV-qualifiers is
+ not substitutable. The natural recursive implementation of the
+ CV-qualifiers would cause subsets to be substitutable, so instead
+ we pull them all off now.
+
+ FIXME: The ABI says that order-insensitive vendor qualifiers
+ should be handled in the same way, but we have no way to tell
+ which vendor qualifiers are order-insensitive and which are
+ order-sensitive. So we just assume that they are all
+ order-sensitive. g++ 3.4 supports only one vendor qualifier,
+ __vector, and it treats it as order-sensitive when mangling
+ names. */
+
+ peek = d_peek_char (di);
+ if (peek == 'r' || peek == 'V' || peek == 'K')
+ {
+ struct demangle_component **pret;
+
+ pret = d_cv_qualifiers (di, &ret, 0);
+ if (pret == NULL)
+ return NULL;
+ if (d_peek_char (di) == 'F')
+ {
+ /* cv-qualifiers before a function type apply to 'this',
+ so avoid adding the unqualified function type to
+ the substitution list. */
+ *pret = d_function_type (di);
+ }
+ else
+ *pret = cplus_demangle_type (di);
+ if (!*pret)
+ return NULL;
+ if ((*pret)->type == DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS
+ || (*pret)->type == DEMANGLE_COMPONENT_REFERENCE_THIS)
+ {
+ /* Move the ref-qualifier outside the cv-qualifiers so that
+ they are printed in the right order. */
+ struct demangle_component *fn = d_left (*pret);
+ d_left (*pret) = ret;
+ ret = *pret;
+ *pret = fn;
+ }
+ if (! d_add_substitution (di, ret))
+ return NULL;
+ return ret;
+ }
+
+ can_subst = 1;
+
+ switch (peek)
+ {
+ case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
+ case 'h': case 'i': case 'j': case 'l': case 'm': case 'n':
+ case 'o': case 's': case 't':
+ case 'v': case 'w': case 'x': case 'y': case 'z':
+ ret = d_make_builtin_type (di,
+ &cplus_demangle_builtin_types[peek - 'a']);
+ di->expansion += ret->u.s_builtin.type->len;
+ can_subst = 0;
+ d_advance (di, 1);
+ break;
+
+ case 'u':
+ d_advance (di, 1);
+ ret = d_make_comp (di, DEMANGLE_COMPONENT_VENDOR_TYPE,
+ d_source_name (di), NULL);
+ break;
+
+ case 'F':
+ ret = d_function_type (di);
+ break;
+
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ case 'N':
+ case 'Z':
+ ret = d_class_enum_type (di);
+ break;
+
+ case 'A':
+ ret = d_array_type (di);
+ break;
+
+ case 'M':
+ ret = d_pointer_to_member_type (di);
+ break;
+
+ case 'T':
+ ret = d_template_param (di);
+ if (d_peek_char (di) == 'I')
+ {
+ /* This may be <template-template-param> <template-args>.
+ If this is the type for a conversion operator, we can
+ have a <template-template-param> here only by following
+ a derivation like this:
+
+ <nested-name>
+ -> <template-prefix> <template-args>
+ -> <prefix> <template-unqualified-name> <template-args>
+ -> <unqualified-name> <template-unqualified-name> <template-args>
+ -> <source-name> <template-unqualified-name> <template-args>
+ -> <source-name> <operator-name> <template-args>
+ -> <source-name> cv <type> <template-args>
+ -> <source-name> cv <template-template-param> <template-args> <template-args>
+
+ where the <template-args> is followed by another.
+ Otherwise, we must have a derivation like this:
+
+ <nested-name>
+ -> <template-prefix> <template-args>
+ -> <prefix> <template-unqualified-name> <template-args>
+ -> <unqualified-name> <template-unqualified-name> <template-args>
+ -> <source-name> <template-unqualified-name> <template-args>
+ -> <source-name> <operator-name> <template-args>
+ -> <source-name> cv <type> <template-args>
+ -> <source-name> cv <template-param> <template-args>
+
+ where we need to leave the <template-args> to be processed
+ by d_prefix (following the <template-prefix>).
+
+ The <template-template-param> part is a substitution
+ candidate. */
+ if (! di->is_conversion)
+ {
+ if (! d_add_substitution (di, ret))
+ return NULL;
+ ret = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, ret,
+ d_template_args (di));
+ }
+ else
+ {
+ struct demangle_component *args;
+ struct d_info_checkpoint checkpoint;
+
+ d_checkpoint (di, &checkpoint);
+ args = d_template_args (di);
+ if (d_peek_char (di) == 'I')
+ {
+ if (! d_add_substitution (di, ret))
+ return NULL;
+ ret = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, ret,
+ args);
+ }
+ else
+ d_backtrack (di, &checkpoint);
+ }
+ }
+ break;
+
+ case 'S':
+ /* If this is a special substitution, then it is the start of
+ <class-enum-type>. */
+ {
+ char peek_next;
+
+ peek_next = d_peek_next_char (di);
+ if (IS_DIGIT (peek_next)
+ || peek_next == '_'
+ || IS_UPPER (peek_next))
+ {
+ ret = d_substitution (di, 0);
+ /* The substituted name may have been a template name and
+ may be followed by tepmlate args. */
+ if (d_peek_char (di) == 'I')
+ ret = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, ret,
+ d_template_args (di));
+ else
+ can_subst = 0;
+ }
+ else
+ {
+ ret = d_class_enum_type (di);
+ /* If the substitution was a complete type, then it is not
+ a new substitution candidate. However, if the
+ substitution was followed by template arguments, then
+ the whole thing is a substitution candidate. */
+ if (ret != NULL && ret->type == DEMANGLE_COMPONENT_SUB_STD)
+ can_subst = 0;
+ }
+ }
+ break;
+
+ case 'O':
+ d_advance (di, 1);
+ ret = d_make_comp (di, DEMANGLE_COMPONENT_RVALUE_REFERENCE,
+ cplus_demangle_type (di), NULL);
+ break;
+
+ case 'P':
+ d_advance (di, 1);
+ ret = d_make_comp (di, DEMANGLE_COMPONENT_POINTER,
+ cplus_demangle_type (di), NULL);
+ break;
+
+ case 'R':
+ d_advance (di, 1);
+ ret = d_make_comp (di, DEMANGLE_COMPONENT_REFERENCE,
+ cplus_demangle_type (di), NULL);
+ break;
+
+ case 'C':
+ d_advance (di, 1);
+ ret = d_make_comp (di, DEMANGLE_COMPONENT_COMPLEX,
+ cplus_demangle_type (di), NULL);
+ break;
+
+ case 'G':
+ d_advance (di, 1);
+ ret = d_make_comp (di, DEMANGLE_COMPONENT_IMAGINARY,
+ cplus_demangle_type (di), NULL);
+ break;
+
+ case 'U':
+ d_advance (di, 1);
+ ret = d_source_name (di);
+ ret = d_make_comp (di, DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL,
+ cplus_demangle_type (di), ret);
+ break;
+
+ case 'D':
+ can_subst = 0;
+ d_advance (di, 1);
+ peek = d_next_char (di);
+ switch (peek)
+ {
+ case 'T':
+ case 't':
+ /* decltype (expression) */
+ ret = d_make_comp (di, DEMANGLE_COMPONENT_DECLTYPE,
+ d_expression (di), NULL);
+ if (ret && d_next_char (di) != 'E')
+ ret = NULL;
+ can_subst = 1;
+ break;
+
+ case 'p':
+ /* Pack expansion. */
+ ret = d_make_comp (di, DEMANGLE_COMPONENT_PACK_EXPANSION,
+ cplus_demangle_type (di), NULL);
+ can_subst = 1;
+ break;
+
+ case 'a':
+ /* auto */
+ ret = d_make_name (di, "auto", 4);
+ break;
+
+ case 'f':
+ /* 32-bit decimal floating point */
+ ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[26]);
+ di->expansion += ret->u.s_builtin.type->len;
+ break;
+ case 'd':
+ /* 64-bit DFP */
+ ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[27]);
+ di->expansion += ret->u.s_builtin.type->len;
+ break;
+ case 'e':
+ /* 128-bit DFP */
+ ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[28]);
+ di->expansion += ret->u.s_builtin.type->len;
+ break;
+ case 'h':
+ /* 16-bit half-precision FP */
+ ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[29]);
+ di->expansion += ret->u.s_builtin.type->len;
+ break;
+ case 's':
+ /* char16_t */
+ ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[30]);
+ di->expansion += ret->u.s_builtin.type->len;
+ break;
+ case 'i':
+ /* char32_t */
+ ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[31]);
+ di->expansion += ret->u.s_builtin.type->len;
+ break;
+
+ case 'F':
+ /* Fixed point types. DF<int bits><length><fract bits><sat> */
+ ret = d_make_empty (di);
+ ret->type = DEMANGLE_COMPONENT_FIXED_TYPE;
+ if ((ret->u.s_fixed.accum = IS_DIGIT (d_peek_char (di))))
+ /* For demangling we don't care about the bits. */
+ d_number (di);
+ ret->u.s_fixed.length = cplus_demangle_type (di);
+ if (ret->u.s_fixed.length == NULL)
+ return NULL;
+ d_number (di);
+ peek = d_next_char (di);
+ ret->u.s_fixed.sat = (peek == 's');
+ break;
+
+ case 'v':
+ ret = d_vector_type (di);
+ can_subst = 1;
+ break;
+
+ case 'n':
+ /* decltype(nullptr) */
+ ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[32]);
+ di->expansion += ret->u.s_builtin.type->len;
+ break;
+
+ default:
+ return NULL;
+ }
+ break;
+
+ default:
+ return NULL;
+ }
+
+ if (can_subst)
+ {
+ if (! d_add_substitution (di, ret))
+ return NULL;
+ }
+
+ return ret;
+}
+
+/* <CV-qualifiers> ::= [r] [V] [K] */
+
+static struct demangle_component **
+d_cv_qualifiers (struct d_info *di,
+ struct demangle_component **pret, int member_fn)
+{
+ struct demangle_component **pstart;
+ char peek;
+
+ pstart = pret;
+ peek = d_peek_char (di);
+ while (peek == 'r' || peek == 'V' || peek == 'K')
+ {
+ enum demangle_component_type t;
+
+ d_advance (di, 1);
+ if (peek == 'r')
+ {
+ t = (member_fn
+ ? DEMANGLE_COMPONENT_RESTRICT_THIS
+ : DEMANGLE_COMPONENT_RESTRICT);
+ di->expansion += sizeof "restrict";
+ }
+ else if (peek == 'V')
+ {
+ t = (member_fn
+ ? DEMANGLE_COMPONENT_VOLATILE_THIS
+ : DEMANGLE_COMPONENT_VOLATILE);
+ di->expansion += sizeof "volatile";
+ }
+ else
+ {
+ t = (member_fn
+ ? DEMANGLE_COMPONENT_CONST_THIS
+ : DEMANGLE_COMPONENT_CONST);
+ di->expansion += sizeof "const";
+ }
+
+ *pret = d_make_comp (di, t, NULL, NULL);
+ if (*pret == NULL)
+ return NULL;
+ pret = &d_left (*pret);
+
+ peek = d_peek_char (di);
+ }
+
+ if (!member_fn && peek == 'F')
+ {
+ while (pstart != pret)
+ {
+ switch ((*pstart)->type)
+ {
+ case DEMANGLE_COMPONENT_RESTRICT:
+ (*pstart)->type = DEMANGLE_COMPONENT_RESTRICT_THIS;
+ break;
+ case DEMANGLE_COMPONENT_VOLATILE:
+ (*pstart)->type = DEMANGLE_COMPONENT_VOLATILE_THIS;
+ break;
+ case DEMANGLE_COMPONENT_CONST:
+ (*pstart)->type = DEMANGLE_COMPONENT_CONST_THIS;
+ break;
+ default:
+ break;
+ }
+ pstart = &d_left (*pstart);
+ }
+ }
+
+ return pret;
+}
+
+/* <ref-qualifier> ::= R
+ ::= O */
+
+static struct demangle_component *
+d_ref_qualifier (struct d_info *di, struct demangle_component *sub)
+{
+ struct demangle_component *ret = sub;
+ char peek;
+
+ peek = d_peek_char (di);
+ if (peek == 'R' || peek == 'O')
+ {
+ enum demangle_component_type t;
+ if (peek == 'R')
+ {
+ t = DEMANGLE_COMPONENT_REFERENCE_THIS;
+ di->expansion += sizeof "&";
+ }
+ else
+ {
+ t = DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS;
+ di->expansion += sizeof "&&";
+ }
+ d_advance (di, 1);
+
+ ret = d_make_comp (di, t, ret, NULL);
+ }
+
+ return ret;
+}
+
+/* <function-type> ::= F [Y] <bare-function-type> [<ref-qualifier>] E */
+
+static struct demangle_component *
+d_function_type (struct d_info *di)
+{
+ struct demangle_component *ret;
+
+ if (! d_check_char (di, 'F'))
+ return NULL;
+ if (d_peek_char (di) == 'Y')
+ {
+ /* Function has C linkage. We don't print this information.
+ FIXME: We should print it in verbose mode. */
+ d_advance (di, 1);
+ }
+ ret = d_bare_function_type (di, 1);
+ ret = d_ref_qualifier (di, ret);
+
+ if (! d_check_char (di, 'E'))
+ return NULL;
+ return ret;
+}
+
+/* <type>+ */
+
+static struct demangle_component *
+d_parmlist (struct d_info *di)
+{
+ struct demangle_component *tl;
+ struct demangle_component **ptl;
+
+ tl = NULL;
+ ptl = &tl;
+ while (1)
+ {
+ struct demangle_component *type;
+
+ char peek = d_peek_char (di);
+ if (peek == '\0' || peek == 'E' || peek == '.')
+ break;
+ if ((peek == 'R' || peek == 'O')
+ && d_peek_next_char (di) == 'E')
+ /* Function ref-qualifier, not a ref prefix for a parameter type. */
+ break;
+ type = cplus_demangle_type (di);
+ if (type == NULL)
+ return NULL;
+ *ptl = d_make_comp (di, DEMANGLE_COMPONENT_ARGLIST, type, NULL);
+ if (*ptl == NULL)
+ return NULL;
+ ptl = &d_right (*ptl);
+ }
+
+ /* There should be at least one parameter type besides the optional
+ return type. A function which takes no arguments will have a
+ single parameter type void. */
+ if (tl == NULL)
+ return NULL;
+
+ /* If we have a single parameter type void, omit it. */
+ if (d_right (tl) == NULL
+ && d_left (tl)->type == DEMANGLE_COMPONENT_BUILTIN_TYPE
+ && d_left (tl)->u.s_builtin.type->print == D_PRINT_VOID)
+ {
+ di->expansion -= d_left (tl)->u.s_builtin.type->len;
+ d_left (tl) = NULL;
+ }
+
+ return tl;
+}
+
+/* <bare-function-type> ::= [J]<type>+ */
+
+static struct demangle_component *
+d_bare_function_type (struct d_info *di, int has_return_type)
+{
+ struct demangle_component *return_type;
+ struct demangle_component *tl;
+ char peek;
+
+ /* Detect special qualifier indicating that the first argument
+ is the return type. */
+ peek = d_peek_char (di);
+ if (peek == 'J')
+ {
+ d_advance (di, 1);
+ has_return_type = 1;
+ }
+
+ if (has_return_type)
+ {
+ return_type = cplus_demangle_type (di);
+ if (return_type == NULL)
+ return NULL;
+ }
+ else
+ return_type = NULL;
+
+ tl = d_parmlist (di);
+ if (tl == NULL)
+ return NULL;
+
+ return d_make_comp (di, DEMANGLE_COMPONENT_FUNCTION_TYPE,
+ return_type, tl);
+}
+
+/* <class-enum-type> ::= <name> */
+
+static struct demangle_component *
+d_class_enum_type (struct d_info *di)
+{
+ return d_name (di);
+}
+
+/* <array-type> ::= A <(positive dimension) number> _ <(element) type>
+ ::= A [<(dimension) expression>] _ <(element) type>
+*/
+
+static struct demangle_component *
+d_array_type (struct d_info *di)
+{
+ char peek;
+ struct demangle_component *dim;
+
+ if (! d_check_char (di, 'A'))
+ return NULL;
+
+ peek = d_peek_char (di);
+ if (peek == '_')
+ dim = NULL;
+ else if (IS_DIGIT (peek))
+ {
+ const char *s;
+
+ s = d_str (di);
+ do
+ {
+ d_advance (di, 1);
+ peek = d_peek_char (di);
+ }
+ while (IS_DIGIT (peek));
+ dim = d_make_name (di, s, d_str (di) - s);
+ if (dim == NULL)
+ return NULL;
+ }
+ else
+ {
+ dim = d_expression (di);
+ if (dim == NULL)
+ return NULL;
+ }
+
+ if (! d_check_char (di, '_'))
+ return NULL;
+
+ return d_make_comp (di, DEMANGLE_COMPONENT_ARRAY_TYPE, dim,
+ cplus_demangle_type (di));
+}
+
+/* <vector-type> ::= Dv <number> _ <type>
+ ::= Dv _ <expression> _ <type> */
+
+static struct demangle_component *
+d_vector_type (struct d_info *di)
+{
+ char peek;
+ struct demangle_component *dim;
+
+ peek = d_peek_char (di);
+ if (peek == '_')
+ {
+ d_advance (di, 1);
+ dim = d_expression (di);
+ }
+ else
+ dim = d_number_component (di);
+
+ if (dim == NULL)
+ return NULL;
+
+ if (! d_check_char (di, '_'))
+ return NULL;
+
+ return d_make_comp (di, DEMANGLE_COMPONENT_VECTOR_TYPE, dim,
+ cplus_demangle_type (di));
+}
+
+/* <pointer-to-member-type> ::= M <(class) type> <(member) type> */
+
+static struct demangle_component *
+d_pointer_to_member_type (struct d_info *di)
+{
+ struct demangle_component *cl;
+ struct demangle_component *mem;
+
+ if (! d_check_char (di, 'M'))
+ return NULL;
+
+ cl = cplus_demangle_type (di);
+ if (cl == NULL)
+ return NULL;
+
+ /* The ABI says, "The type of a non-static member function is considered
+ to be different, for the purposes of substitution, from the type of a
+ namespace-scope or static member function whose type appears
+ similar. The types of two non-static member functions are considered
+ to be different, for the purposes of substitution, if the functions
+ are members of different classes. In other words, for the purposes of
+ substitution, the class of which the function is a member is
+ considered part of the type of function."
+
+ For a pointer to member function, this call to cplus_demangle_type
+ will end up adding a (possibly qualified) non-member function type to
+ the substitution table, which is not correct; however, the member
+ function type will never be used in a substitution, so putting the
+ wrong type in the substitution table is harmless. */
+
+ mem = cplus_demangle_type (di);
+ if (mem == NULL)
+ return NULL;
+
+ return d_make_comp (di, DEMANGLE_COMPONENT_PTRMEM_TYPE, cl, mem);
+}
+
+/* <non-negative number> _ */
+
+static long
+d_compact_number (struct d_info *di)
+{
+ long num;
+ if (d_peek_char (di) == '_')
+ num = 0;
+ else if (d_peek_char (di) == 'n')
+ return -1;
+ else
+ num = d_number (di) + 1;
+
+ if (! d_check_char (di, '_'))
+ return -1;
+ return num;
+}
+
+/* <template-param> ::= T_
+ ::= T <(parameter-2 non-negative) number> _
+*/
+
+static struct demangle_component *
+d_template_param (struct d_info *di)
+{
+ long param;
+
+ if (! d_check_char (di, 'T'))
+ return NULL;
+
+ param = d_compact_number (di);
+ if (param < 0)
+ return NULL;
+
+ ++di->did_subs;
+
+ return d_make_template_param (di, param);
+}
+
+/* <template-args> ::= I <template-arg>+ E */
+
+static struct demangle_component *
+d_template_args (struct d_info *di)
+{
+ struct demangle_component *hold_last_name;
+ struct demangle_component *al;
+ struct demangle_component **pal;
+
+ /* Preserve the last name we saw--don't let the template arguments
+ clobber it, as that would give us the wrong name for a subsequent
+ constructor or destructor. */
+ hold_last_name = di->last_name;
+
+ if (d_peek_char (di) != 'I'
+ && d_peek_char (di) != 'J')
+ return NULL;
+ d_advance (di, 1);
+
+ if (d_peek_char (di) == 'E')
+ {
+ /* An argument pack can be empty. */
+ d_advance (di, 1);
+ return d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE_ARGLIST, NULL, NULL);
+ }
+
+ al = NULL;
+ pal = &al;
+ while (1)
+ {
+ struct demangle_component *a;
+
+ a = d_template_arg (di);
+ if (a == NULL)
+ return NULL;
+
+ *pal = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE_ARGLIST, a, NULL);
+ if (*pal == NULL)
+ return NULL;
+ pal = &d_right (*pal);
+
+ if (d_peek_char (di) == 'E')
+ {
+ d_advance (di, 1);
+ break;
+ }
+ }
+
+ di->last_name = hold_last_name;
+
+ return al;
+}
+
+/* <template-arg> ::= <type>
+ ::= X <expression> E
+ ::= <expr-primary>
+*/
+
+static struct demangle_component *
+d_template_arg (struct d_info *di)
+{
+ struct demangle_component *ret;
+
+ switch (d_peek_char (di))
+ {
+ case 'X':
+ d_advance (di, 1);
+ ret = d_expression (di);
+ if (! d_check_char (di, 'E'))
+ return NULL;
+ return ret;
+
+ case 'L':
+ return d_expr_primary (di);
+
+ case 'I':
+ case 'J':
+ /* An argument pack. */
+ return d_template_args (di);
+
+ default:
+ return cplus_demangle_type (di);
+ }
+}
+
+/* Parse a sequence of expressions until we hit the terminator
+ character. */
+
+static struct demangle_component *
+d_exprlist (struct d_info *di, char terminator)
+{
+ struct demangle_component *list = NULL;
+ struct demangle_component **p = &list;
+
+ if (d_peek_char (di) == terminator)
+ {
+ d_advance (di, 1);
+ return d_make_comp (di, DEMANGLE_COMPONENT_ARGLIST, NULL, NULL);
+ }
+
+ while (1)
+ {
+ struct demangle_component *arg = d_expression (di);
+ if (arg == NULL)
+ return NULL;
+
+ *p = d_make_comp (di, DEMANGLE_COMPONENT_ARGLIST, arg, NULL);
+ if (*p == NULL)
+ return NULL;
+ p = &d_right (*p);
+
+ if (d_peek_char (di) == terminator)
+ {
+ d_advance (di, 1);
+ break;
+ }
+ }
+
+ return list;
+}
+
+/* Returns nonzero iff OP is an operator for a C++ cast: const_cast,
+ dynamic_cast, static_cast or reinterpret_cast. */
+
+static int
+op_is_new_cast (struct demangle_component *op)
+{
+ const char *code = op->u.s_operator.op->code;
+ return (code[1] == 'c'
+ && (code[0] == 's' || code[0] == 'd'
+ || code[0] == 'c' || code[0] == 'r'));
+}
+
+/* <expression> ::= <(unary) operator-name> <expression>
+ ::= <(binary) operator-name> <expression> <expression>
+ ::= <(trinary) operator-name> <expression> <expression> <expression>
+ ::= cl <expression>+ E
+ ::= st <type>
+ ::= <template-param>
+ ::= sr <type> <unqualified-name>
+ ::= sr <type> <unqualified-name> <template-args>
+ ::= <expr-primary>
+*/
+
+static inline struct demangle_component *
+d_expression_1 (struct d_info *di)
+{
+ char peek;
+
+ peek = d_peek_char (di);
+ if (peek == 'L')
+ return d_expr_primary (di);
+ else if (peek == 'T')
+ return d_template_param (di);
+ else if (peek == 's' && d_peek_next_char (di) == 'r')
+ {
+ struct demangle_component *type;
+ struct demangle_component *name;
+
+ d_advance (di, 2);
+ type = cplus_demangle_type (di);
+ name = d_unqualified_name (di);
+ if (d_peek_char (di) != 'I')
+ return d_make_comp (di, DEMANGLE_COMPONENT_QUAL_NAME, type, name);
+ else
+ return d_make_comp (di, DEMANGLE_COMPONENT_QUAL_NAME, type,
+ d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, name,
+ d_template_args (di)));
+ }
+ else if (peek == 's' && d_peek_next_char (di) == 'p')
+ {
+ d_advance (di, 2);
+ return d_make_comp (di, DEMANGLE_COMPONENT_PACK_EXPANSION,
+ d_expression_1 (di), NULL);
+ }
+ else if (peek == 'f' && d_peek_next_char (di) == 'p')
+ {
+ /* Function parameter used in a late-specified return type. */
+ int index;
+ d_advance (di, 2);
+ if (d_peek_char (di) == 'T')
+ {
+ /* 'this' parameter. */
+ d_advance (di, 1);
+ index = 0;
+ }
+ else
+ {
+ index = d_compact_number (di) + 1;
+ if (index == 0)
+ return NULL;
+ }
+ return d_make_function_param (di, index);
+ }
+ else if (IS_DIGIT (peek)
+ || (peek == 'o' && d_peek_next_char (di) == 'n'))
+ {
+ /* We can get an unqualified name as an expression in the case of
+ a dependent function call, i.e. decltype(f(t)). */
+ struct demangle_component *name;
+
+ if (peek == 'o')
+ /* operator-function-id, i.e. operator+(t). */
+ d_advance (di, 2);
+
+ name = d_unqualified_name (di);
+ if (name == NULL)
+ return NULL;
+ if (d_peek_char (di) == 'I')
+ return d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, name,
+ d_template_args (di));
+ else
+ return name;
+ }
+ else if ((peek == 'i' || peek == 't')
+ && d_peek_next_char (di) == 'l')
+ {
+ /* Brace-enclosed initializer list, untyped or typed. */
+ struct demangle_component *type = NULL;
+ if (peek == 't')
+ type = cplus_demangle_type (di);
+ d_advance (di, 2);
+ return d_make_comp (di, DEMANGLE_COMPONENT_INITIALIZER_LIST,
+ type, d_exprlist (di, 'E'));
+ }
+ else
+ {
+ struct demangle_component *op;
+ const char *code = NULL;
+ int args;
+
+ op = d_operator_name (di);
+ if (op == NULL)
+ return NULL;
+
+ if (op->type == DEMANGLE_COMPONENT_OPERATOR)
+ {
+ code = op->u.s_operator.op->code;
+ di->expansion += op->u.s_operator.op->len - 2;
+ if (strcmp (code, "st") == 0)
+ return d_make_comp (di, DEMANGLE_COMPONENT_UNARY, op,
+ cplus_demangle_type (di));
+ }
+
+ switch (op->type)
+ {
+ default:
+ return NULL;
+ case DEMANGLE_COMPONENT_OPERATOR:
+ args = op->u.s_operator.op->args;
+ break;
+ case DEMANGLE_COMPONENT_EXTENDED_OPERATOR:
+ args = op->u.s_extended_operator.args;
+ break;
+ case DEMANGLE_COMPONENT_CAST:
+ args = 1;
+ break;
+ }
+
+ switch (args)
+ {
+ case 0:
+ return d_make_comp (di, DEMANGLE_COMPONENT_NULLARY, op, NULL);
+
+ case 1:
+ {
+ struct demangle_component *operand;
+ int suffix = 0;
+
+ if (code && (code[0] == 'p' || code[0] == 'm')
+ && code[1] == code[0])
+ /* pp_ and mm_ are the prefix variants. */
+ suffix = !d_check_char (di, '_');
+
+ if (op->type == DEMANGLE_COMPONENT_CAST
+ && d_check_char (di, '_'))
+ operand = d_exprlist (di, 'E');
+ else
+ operand = d_expression_1 (di);
+
+ if (suffix)
+ /* Indicate the suffix variant for d_print_comp. */
+ return d_make_comp (di, DEMANGLE_COMPONENT_UNARY, op,
+ d_make_comp (di,
+ DEMANGLE_COMPONENT_BINARY_ARGS,
+ operand, operand));
+ else
+ return d_make_comp (di, DEMANGLE_COMPONENT_UNARY, op,
+ operand);
+ }
+ case 2:
+ {
+ struct demangle_component *left;
+ struct demangle_component *right;
+
+ if (op_is_new_cast (op))
+ left = cplus_demangle_type (di);
+ else
+ left = d_expression_1 (di);
+ if (!strcmp (code, "cl"))
+ right = d_exprlist (di, 'E');
+ else if (!strcmp (code, "dt") || !strcmp (code, "pt"))
+ {
+ right = d_unqualified_name (di);
+ if (d_peek_char (di) == 'I')
+ right = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE,
+ right, d_template_args (di));
+ }
+ else
+ right = d_expression_1 (di);
+
+ return d_make_comp (di, DEMANGLE_COMPONENT_BINARY, op,
+ d_make_comp (di,
+ DEMANGLE_COMPONENT_BINARY_ARGS,
+ left, right));
+ }
+ case 3:
+ {
+ struct demangle_component *first;
+ struct demangle_component *second;
+ struct demangle_component *third;
+
+ if (!strcmp (code, "qu"))
+ {
+ /* ?: expression. */
+ first = d_expression_1 (di);
+ second = d_expression_1 (di);
+ third = d_expression_1 (di);
+ }
+ else if (code[0] == 'n')
+ {
+ /* new-expression. */
+ if (code[1] != 'w' && code[1] != 'a')
+ return NULL;
+ first = d_exprlist (di, '_');
+ second = cplus_demangle_type (di);
+ if (d_peek_char (di) == 'E')
+ {
+ d_advance (di, 1);
+ third = NULL;
+ }
+ else if (d_peek_char (di) == 'p'
+ && d_peek_next_char (di) == 'i')
+ {
+ /* Parenthesized initializer. */
+ d_advance (di, 2);
+ third = d_exprlist (di, 'E');
+ }
+ else if (d_peek_char (di) == 'i'
+ && d_peek_next_char (di) == 'l')
+ /* initializer-list. */
+ third = d_expression_1 (di);
+ else
+ return NULL;
+ }
+ else
+ return NULL;
+ return d_make_comp (di, DEMANGLE_COMPONENT_TRINARY, op,
+ d_make_comp (di,
+ DEMANGLE_COMPONENT_TRINARY_ARG1,
+ first,
+ d_make_comp (di,
+ DEMANGLE_COMPONENT_TRINARY_ARG2,
+ second, third)));
+ }
+ default:
+ return NULL;
+ }
+ }
+}
+
+static struct demangle_component *
+d_expression (struct d_info *di)
+{
+ struct demangle_component *ret;
+ int was_expression = di->is_expression;
+
+ di->is_expression = 1;
+ ret = d_expression_1 (di);
+ di->is_expression = was_expression;
+ return ret;
+}
+
+/* <expr-primary> ::= L <type> <(value) number> E
+ ::= L <type> <(value) float> E
+ ::= L <mangled-name> E
+*/
+
+static struct demangle_component *
+d_expr_primary (struct d_info *di)
+{
+ struct demangle_component *ret;
+
+ if (! d_check_char (di, 'L'))
+ return NULL;
+ if (d_peek_char (di) == '_'
+ /* Workaround for G++ bug; see comment in write_template_arg. */
+ || d_peek_char (di) == 'Z')
+ ret = cplus_demangle_mangled_name (di, 0);
+ else
+ {
+ struct demangle_component *type;
+ enum demangle_component_type t;
+ const char *s;
+
+ type = cplus_demangle_type (di);
+ if (type == NULL)
+ return NULL;
+
+ /* If we have a type we know how to print, we aren't going to
+ print the type name itself. */
+ if (type->type == DEMANGLE_COMPONENT_BUILTIN_TYPE
+ && type->u.s_builtin.type->print != D_PRINT_DEFAULT)
+ di->expansion -= type->u.s_builtin.type->len;
+
+ /* Rather than try to interpret the literal value, we just
+ collect it as a string. Note that it's possible to have a
+ floating point literal here. The ABI specifies that the
+ format of such literals is machine independent. That's fine,
+ but what's not fine is that versions of g++ up to 3.2 with
+ -fabi-version=1 used upper case letters in the hex constant,
+ and dumped out gcc's internal representation. That makes it
+ hard to tell where the constant ends, and hard to dump the
+ constant in any readable form anyhow. We don't attempt to
+ handle these cases. */
+
+ t = DEMANGLE_COMPONENT_LITERAL;
+ if (d_peek_char (di) == 'n')
+ {
+ t = DEMANGLE_COMPONENT_LITERAL_NEG;
+ d_advance (di, 1);
+ }
+ s = d_str (di);
+ while (d_peek_char (di) != 'E')
+ {
+ if (d_peek_char (di) == '\0')
+ return NULL;
+ d_advance (di, 1);
+ }
+ ret = d_make_comp (di, t, type, d_make_name (di, s, d_str (di) - s));
+ }
+ if (! d_check_char (di, 'E'))
+ return NULL;
+ return ret;
+}
+
+/* <local-name> ::= Z <(function) encoding> E <(entity) name> [<discriminator>]
+ ::= Z <(function) encoding> E s [<discriminator>]
+ ::= Z <(function) encoding> E d [<parameter> number>] _ <entity name>
+*/
+
+static struct demangle_component *
+d_local_name (struct d_info *di)
+{
+ struct demangle_component *function;
+
+ if (! d_check_char (di, 'Z'))
+ return NULL;
+
+ function = d_encoding (di, 0);
+
+ if (! d_check_char (di, 'E'))
+ return NULL;
+
+ if (d_peek_char (di) == 's')
+ {
+ d_advance (di, 1);
+ if (! d_discriminator (di))
+ return NULL;
+ return d_make_comp (di, DEMANGLE_COMPONENT_LOCAL_NAME, function,
+ d_make_name (di, "string literal",
+ sizeof "string literal" - 1));
+ }
+ else
+ {
+ struct demangle_component *name;
+ int num = -1;
+
+ if (d_peek_char (di) == 'd')
+ {
+ /* Default argument scope: d <number> _. */
+ d_advance (di, 1);
+ num = d_compact_number (di);
+ if (num < 0)
+ return NULL;
+ }
+
+ name = d_name (di);
+ if (name)
+ switch (name->type)
+ {
+ /* Lambdas and unnamed types have internal discriminators. */
+ case DEMANGLE_COMPONENT_LAMBDA:
+ case DEMANGLE_COMPONENT_UNNAMED_TYPE:
+ break;
+ default:
+ if (! d_discriminator (di))
+ return NULL;
+ }
+ if (num >= 0)
+ name = d_make_default_arg (di, num, name);
+ return d_make_comp (di, DEMANGLE_COMPONENT_LOCAL_NAME, function, name);
+ }
+}
+
+/* <discriminator> ::= _ <(non-negative) number>
+
+ We demangle the discriminator, but we don't print it out. FIXME:
+ We should print it out in verbose mode. */
+
+static int
+d_discriminator (struct d_info *di)
+{
+ long discrim;
+
+ if (d_peek_char (di) != '_')
+ return 1;
+ d_advance (di, 1);
+ discrim = d_number (di);
+ if (discrim < 0)
+ return 0;
+ return 1;
+}
+
+/* <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _ */
+
+static struct demangle_component *
+d_lambda (struct d_info *di)
+{
+ struct demangle_component *tl;
+ struct demangle_component *ret;
+ int num;
+
+ if (! d_check_char (di, 'U'))
+ return NULL;
+ if (! d_check_char (di, 'l'))
+ return NULL;
+
+ tl = d_parmlist (di);
+ if (tl == NULL)
+ return NULL;
+
+ if (! d_check_char (di, 'E'))
+ return NULL;
+
+ num = d_compact_number (di);
+ if (num < 0)
+ return NULL;
+
+ ret = d_make_empty (di);
+ if (ret)
+ {
+ ret->type = DEMANGLE_COMPONENT_LAMBDA;
+ ret->u.s_unary_num.sub = tl;
+ ret->u.s_unary_num.num = num;
+ }
+
+ if (! d_add_substitution (di, ret))
+ return NULL;
+
+ return ret;
+}
+
+/* <unnamed-type-name> ::= Ut [ <nonnegative number> ] _ */
+
+static struct demangle_component *
+d_unnamed_type (struct d_info *di)
+{
+ struct demangle_component *ret;
+ long num;
+
+ if (! d_check_char (di, 'U'))
+ return NULL;
+ if (! d_check_char (di, 't'))
+ return NULL;
+
+ num = d_compact_number (di);
+ if (num < 0)
+ return NULL;
+
+ ret = d_make_empty (di);
+ if (ret)
+ {
+ ret->type = DEMANGLE_COMPONENT_UNNAMED_TYPE;
+ ret->u.s_number.number = num;
+ }
+
+ if (! d_add_substitution (di, ret))
+ return NULL;
+
+ return ret;
+}
+
+/* <clone-suffix> ::= [ . <clone-type-identifier> ] [ . <nonnegative number> ]*
+*/
+
+static struct demangle_component *
+d_clone_suffix (struct d_info *di, struct demangle_component *encoding)
+{
+ const char *suffix = d_str (di);
+ const char *pend = suffix;
+ struct demangle_component *n;
+
+ if (*pend == '.' && (IS_LOWER (pend[1]) || pend[1] == '_'))
+ {
+ pend += 2;
+ while (IS_LOWER (*pend) || *pend == '_')
+ ++pend;
+ }
+ while (*pend == '.' && IS_DIGIT (pend[1]))
+ {
+ pend += 2;
+ while (IS_DIGIT (*pend))
+ ++pend;
+ }
+ d_advance (di, pend - suffix);
+ n = d_make_name (di, suffix, pend - suffix);
+ return d_make_comp (di, DEMANGLE_COMPONENT_CLONE, encoding, n);
+}
+
+/* Add a new substitution. */
+
+static int
+d_add_substitution (struct d_info *di, struct demangle_component *dc)
+{
+ if (dc == NULL)
+ return 0;
+ if (di->next_sub >= di->num_subs)
+ return 0;
+ di->subs[di->next_sub] = dc;
+ ++di->next_sub;
+ return 1;
+}
+
+/* <substitution> ::= S <seq-id> _
+ ::= S_
+ ::= St
+ ::= Sa
+ ::= Sb
+ ::= Ss
+ ::= Si
+ ::= So
+ ::= Sd
+
+ If PREFIX is non-zero, then this type is being used as a prefix in
+ a qualified name. In this case, for the standard substitutions, we
+ need to check whether we are being used as a prefix for a
+ constructor or destructor, and return a full template name.
+ Otherwise we will get something like std::iostream::~iostream()
+ which does not correspond particularly well to any function which
+ actually appears in the source.
+*/
+
+static const struct d_standard_sub_info standard_subs[] =
+{
+ { 't', NL ("std"),
+ NL ("std"),
+ NULL, 0 },
+ { 'a', NL ("std::allocator"),
+ NL ("std::allocator"),
+ NL ("allocator") },
+ { 'b', NL ("std::basic_string"),
+ NL ("std::basic_string"),
+ NL ("basic_string") },
+ { 's', NL ("std::string"),
+ NL ("std::basic_string<char, std::char_traits<char>, std::allocator<char> >"),
+ NL ("basic_string") },
+ { 'i', NL ("std::istream"),
+ NL ("std::basic_istream<char, std::char_traits<char> >"),
+ NL ("basic_istream") },
+ { 'o', NL ("std::ostream"),
+ NL ("std::basic_ostream<char, std::char_traits<char> >"),
+ NL ("basic_ostream") },
+ { 'd', NL ("std::iostream"),
+ NL ("std::basic_iostream<char, std::char_traits<char> >"),
+ NL ("basic_iostream") }
+};
+
+static struct demangle_component *
+d_substitution (struct d_info *di, int prefix)
+{
+ char c;
+
+ if (! d_check_char (di, 'S'))
+ return NULL;
+
+ c = d_next_char (di);
+ if (c == '_' || IS_DIGIT (c) || IS_UPPER (c))
+ {
+ unsigned int id;
+
+ id = 0;
+ if (c != '_')
+ {
+ do
+ {
+ unsigned int new_id;
+
+ if (IS_DIGIT (c))
+ new_id = id * 36 + c - '0';
+ else if (IS_UPPER (c))
+ new_id = id * 36 + c - 'A' + 10;
+ else
+ return NULL;
+ if (new_id < id)
+ return NULL;
+ id = new_id;
+ c = d_next_char (di);
+ }
+ while (c != '_');
+
+ ++id;
+ }
+
+ if (id >= (unsigned int) di->next_sub)
+ return NULL;
+
+ ++di->did_subs;
+
+ return di->subs[id];
+ }
+ else
+ {
+ int verbose;
+ const struct d_standard_sub_info *p;
+ const struct d_standard_sub_info *pend;
+
+ verbose = (di->options & DMGL_VERBOSE) != 0;
+ if (! verbose && prefix)
+ {
+ char peek;
+
+ peek = d_peek_char (di);
+ if (peek == 'C' || peek == 'D')
+ verbose = 1;
+ }
+
+ pend = (&standard_subs[0]
+ + sizeof standard_subs / sizeof standard_subs[0]);
+ for (p = &standard_subs[0]; p < pend; ++p)
+ {
+ if (c == p->code)
+ {
+ const char *s;
+ int len;
+
+ if (p->set_last_name != NULL)
+ di->last_name = d_make_sub (di, p->set_last_name,
+ p->set_last_name_len);
+ if (verbose)
+ {
+ s = p->full_expansion;
+ len = p->full_len;
+ }
+ else
+ {
+ s = p->simple_expansion;
+ len = p->simple_len;
+ }
+ di->expansion += len;
+ return d_make_sub (di, s, len);
+ }
+ }
+
+ return NULL;
+ }
+}
+
+static void
+d_checkpoint (struct d_info *di, struct d_info_checkpoint *checkpoint)
+{
+ checkpoint->n = di->n;
+ checkpoint->next_comp = di->next_comp;
+ checkpoint->next_sub = di->next_sub;
+ checkpoint->did_subs = di->did_subs;
+ checkpoint->expansion = di->expansion;
+}
+
+static void
+d_backtrack (struct d_info *di, struct d_info_checkpoint *checkpoint)
+{
+ di->n = checkpoint->n;
+ di->next_comp = checkpoint->next_comp;
+ di->next_sub = checkpoint->next_sub;
+ di->did_subs = checkpoint->did_subs;
+ di->expansion = checkpoint->expansion;
+}
+
+/* Initialize a growable string. */
+
+static void
+d_growable_string_init (struct d_growable_string *dgs, size_t estimate)
+{
+ dgs->buf = NULL;
+ dgs->len = 0;
+ dgs->alc = 0;
+ dgs->allocation_failure = 0;
+
+ if (estimate > 0)
+ d_growable_string_resize (dgs, estimate);
+}
+
+/* Grow a growable string to a given size. */
+
+static inline void
+d_growable_string_resize (struct d_growable_string *dgs, size_t need)
+{
+ size_t newalc;
+ char *newbuf;
+
+ if (dgs->allocation_failure)
+ return;
+
+ /* Start allocation at two bytes to avoid any possibility of confusion
+ with the special value of 1 used as a return in *palc to indicate
+ allocation failures. */
+ newalc = dgs->alc > 0 ? dgs->alc : 2;
+ while (newalc < need)
+ newalc <<= 1;
+
+ newbuf = (char *) realloc (dgs->buf, newalc);
+ if (newbuf == NULL)
+ {
+ free (dgs->buf);
+ dgs->buf = NULL;
+ dgs->len = 0;
+ dgs->alc = 0;
+ dgs->allocation_failure = 1;
+ return;
+ }
+ dgs->buf = newbuf;
+ dgs->alc = newalc;
+}
+
+/* Append a buffer to a growable string. */
+
+static inline void
+d_growable_string_append_buffer (struct d_growable_string *dgs,
+ const char *s, size_t l)
+{
+ size_t need;
+
+ need = dgs->len + l + 1;
+ if (need > dgs->alc)
+ d_growable_string_resize (dgs, need);
+
+ if (dgs->allocation_failure)
+ return;
+
+ memcpy (dgs->buf + dgs->len, s, l);
+ dgs->buf[dgs->len + l] = '\0';
+ dgs->len += l;
+}
+
+/* Bridge growable strings to the callback mechanism. */
+
+static void
+d_growable_string_callback_adapter (const char *s, size_t l, void *opaque)
+{
+ struct d_growable_string *dgs = (struct d_growable_string*) opaque;
+
+ d_growable_string_append_buffer (dgs, s, l);
+}
+
+/* Walk the tree, counting the number of templates encountered, and
+ the number of times a scope might be saved. These counts will be
+ used to allocate data structures for d_print_comp, so the logic
+ here must mirror the logic d_print_comp will use. It is not
+ important that the resulting numbers are exact, so long as they
+ are larger than the actual numbers encountered. */
+
+static void
+d_count_templates_scopes (int *num_templates, int *num_scopes,
+ const struct demangle_component *dc)
+{
+ if (dc == NULL)
+ return;
+
+ switch (dc->type)
+ {
+ case DEMANGLE_COMPONENT_NAME:
+ case DEMANGLE_COMPONENT_TEMPLATE_PARAM:
+ case DEMANGLE_COMPONENT_FUNCTION_PARAM:
+ case DEMANGLE_COMPONENT_SUB_STD:
+ case DEMANGLE_COMPONENT_BUILTIN_TYPE:
+ case DEMANGLE_COMPONENT_OPERATOR:
+ case DEMANGLE_COMPONENT_CHARACTER:
+ case DEMANGLE_COMPONENT_NUMBER:
+ case DEMANGLE_COMPONENT_UNNAMED_TYPE:
+ break;
+
+ case DEMANGLE_COMPONENT_TEMPLATE:
+ (*num_templates)++;
+ goto recurse_left_right;
+
+ case DEMANGLE_COMPONENT_REFERENCE:
+ case DEMANGLE_COMPONENT_RVALUE_REFERENCE:
+ if (d_left (dc)->type == DEMANGLE_COMPONENT_TEMPLATE_PARAM)
+ (*num_scopes)++;
+ goto recurse_left_right;
+
+ case DEMANGLE_COMPONENT_QUAL_NAME:
+ case DEMANGLE_COMPONENT_LOCAL_NAME:
+ case DEMANGLE_COMPONENT_TYPED_NAME:
+ case DEMANGLE_COMPONENT_VTABLE:
+ case DEMANGLE_COMPONENT_VTT:
+ case DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE:
+ case DEMANGLE_COMPONENT_TYPEINFO:
+ case DEMANGLE_COMPONENT_TYPEINFO_NAME:
+ case DEMANGLE_COMPONENT_TYPEINFO_FN:
+ case DEMANGLE_COMPONENT_THUNK:
+ case DEMANGLE_COMPONENT_VIRTUAL_THUNK:
+ case DEMANGLE_COMPONENT_COVARIANT_THUNK:
+ case DEMANGLE_COMPONENT_JAVA_CLASS:
+ case DEMANGLE_COMPONENT_GUARD:
+ case DEMANGLE_COMPONENT_TLS_INIT:
+ case DEMANGLE_COMPONENT_TLS_WRAPPER:
+ case DEMANGLE_COMPONENT_REFTEMP:
+ case DEMANGLE_COMPONENT_HIDDEN_ALIAS:
+ case DEMANGLE_COMPONENT_RESTRICT:
+ case DEMANGLE_COMPONENT_VOLATILE:
+ case DEMANGLE_COMPONENT_CONST:
+ case DEMANGLE_COMPONENT_RESTRICT_THIS:
+ case DEMANGLE_COMPONENT_VOLATILE_THIS:
+ case DEMANGLE_COMPONENT_CONST_THIS:
+ case DEMANGLE_COMPONENT_REFERENCE_THIS:
+ case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS:
+ case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL:
+ case DEMANGLE_COMPONENT_POINTER:
+ case DEMANGLE_COMPONENT_COMPLEX:
+ case DEMANGLE_COMPONENT_IMAGINARY:
+ case DEMANGLE_COMPONENT_VENDOR_TYPE:
+ case DEMANGLE_COMPONENT_FUNCTION_TYPE:
+ case DEMANGLE_COMPONENT_ARRAY_TYPE:
+ case DEMANGLE_COMPONENT_PTRMEM_TYPE:
+ case DEMANGLE_COMPONENT_FIXED_TYPE:
+ case DEMANGLE_COMPONENT_VECTOR_TYPE:
+ case DEMANGLE_COMPONENT_ARGLIST:
+ case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST:
+ case DEMANGLE_COMPONENT_INITIALIZER_LIST:
+ case DEMANGLE_COMPONENT_CAST:
+ case DEMANGLE_COMPONENT_NULLARY:
+ case DEMANGLE_COMPONENT_UNARY:
+ case DEMANGLE_COMPONENT_BINARY:
+ case DEMANGLE_COMPONENT_BINARY_ARGS:
+ case DEMANGLE_COMPONENT_TRINARY:
+ case DEMANGLE_COMPONENT_TRINARY_ARG1:
+ case DEMANGLE_COMPONENT_TRINARY_ARG2:
+ case DEMANGLE_COMPONENT_LITERAL:
+ case DEMANGLE_COMPONENT_LITERAL_NEG:
+ case DEMANGLE_COMPONENT_JAVA_RESOURCE:
+ case DEMANGLE_COMPONENT_COMPOUND_NAME:
+ case DEMANGLE_COMPONENT_DECLTYPE:
+ case DEMANGLE_COMPONENT_TRANSACTION_CLONE:
+ case DEMANGLE_COMPONENT_NONTRANSACTION_CLONE:
+ case DEMANGLE_COMPONENT_PACK_EXPANSION:
+ case DEMANGLE_COMPONENT_TAGGED_NAME:
+ case DEMANGLE_COMPONENT_CLONE:
+ recurse_left_right:
+ d_count_templates_scopes (num_templates, num_scopes,
+ d_left (dc));
+ d_count_templates_scopes (num_templates, num_scopes,
+ d_right (dc));
+ break;
+
+ case DEMANGLE_COMPONENT_CTOR:
+ d_count_templates_scopes (num_templates, num_scopes,
+ dc->u.s_ctor.name);
+ break;
+
+ case DEMANGLE_COMPONENT_DTOR:
+ d_count_templates_scopes (num_templates, num_scopes,
+ dc->u.s_dtor.name);
+ break;
+
+ case DEMANGLE_COMPONENT_EXTENDED_OPERATOR:
+ d_count_templates_scopes (num_templates, num_scopes,
+ dc->u.s_extended_operator.name);
+ break;
+
+ case DEMANGLE_COMPONENT_GLOBAL_CONSTRUCTORS:
+ case DEMANGLE_COMPONENT_GLOBAL_DESTRUCTORS:
+ d_count_templates_scopes (num_templates, num_scopes,
+ d_left (dc));
+ break;
+
+ case DEMANGLE_COMPONENT_LAMBDA:
+ case DEMANGLE_COMPONENT_DEFAULT_ARG:
+ d_count_templates_scopes (num_templates, num_scopes,
+ dc->u.s_unary_num.sub);
+ break;
+ }
+}
+
+/* Initialize a print information structure. */
+
+static void
+d_print_init (struct d_print_info *dpi, demangle_callbackref callback,
+ void *opaque, const struct demangle_component *dc)
+{
+ dpi->len = 0;
+ dpi->last_char = '\0';
+ dpi->templates = NULL;
+ dpi->modifiers = NULL;
+ dpi->pack_index = 0;
+ dpi->flush_count = 0;
+
+ dpi->callback = callback;
+ dpi->opaque = opaque;
+
+ dpi->demangle_failure = 0;
+
+ dpi->saved_scopes = NULL;
+ dpi->next_saved_scope = 0;
+ dpi->num_saved_scopes = 0;
+
+ dpi->copy_templates = NULL;
+ dpi->next_copy_template = 0;
+ dpi->num_copy_templates = 0;
+
+ d_count_templates_scopes (&dpi->num_copy_templates,
+ &dpi->num_saved_scopes, dc);
+ dpi->num_copy_templates *= dpi->num_saved_scopes;
+
+ dpi->current_template = NULL;
+}
+
+/* Indicate that an error occurred during printing, and test for error. */
+
+static inline void
+d_print_error (struct d_print_info *dpi)
+{
+ dpi->demangle_failure = 1;
+}
+
+static inline int
+d_print_saw_error (struct d_print_info *dpi)
+{
+ return dpi->demangle_failure != 0;
+}
+
+/* Flush buffered characters to the callback. */
+
+static inline void
+d_print_flush (struct d_print_info *dpi)
+{
+ dpi->buf[dpi->len] = '\0';
+ dpi->callback (dpi->buf, dpi->len, dpi->opaque);
+ dpi->len = 0;
+ dpi->flush_count++;
+}
+
+/* Append characters and buffers for printing. */
+
+static inline void
+d_append_char (struct d_print_info *dpi, char c)
+{
+ if (dpi->len == sizeof (dpi->buf) - 1)
+ d_print_flush (dpi);
+
+ dpi->buf[dpi->len++] = c;
+ dpi->last_char = c;
+}
+
+static inline void
+d_append_buffer (struct d_print_info *dpi, const char *s, size_t l)
+{
+ size_t i;
+
+ for (i = 0; i < l; i++)
+ d_append_char (dpi, s[i]);
+}
+
+static inline void
+d_append_string (struct d_print_info *dpi, const char *s)
+{
+ d_append_buffer (dpi, s, strlen (s));
+}
+
+static inline void
+d_append_num (struct d_print_info *dpi, long l)
+{
+ char buf[25];
+ sprintf (buf,"%ld", l);
+ d_append_string (dpi, buf);
+}
+
+static inline char
+d_last_char (struct d_print_info *dpi)
+{
+ return dpi->last_char;
+}
+
+/* Turn components into a human readable string. OPTIONS is the
+ options bits passed to the demangler. DC is the tree to print.
+ CALLBACK is a function to call to flush demangled string segments
+ as they fill the intermediate buffer, and OPAQUE is a generalized
+ callback argument. On success, this returns 1. On failure,
+ it returns 0, indicating a bad parse. It does not use heap
+ memory to build an output string, so cannot encounter memory
+ allocation failure. */
+
+CP_STATIC_IF_GLIBCPP_V3
+int
+cplus_demangle_print_callback (int options,
+ const struct demangle_component *dc,
+ demangle_callbackref callback, void *opaque)
+{
+ struct d_print_info dpi;
+
+ d_print_init (&dpi, callback, opaque, dc);
+
+ {
+#ifdef CP_DYNAMIC_ARRAYS
+ __extension__ struct d_saved_scope scopes[dpi.num_saved_scopes];
+ __extension__ struct d_print_template temps[dpi.num_copy_templates];
+
+ dpi.saved_scopes = scopes;
+ dpi.copy_templates = temps;
+#else
+ dpi.saved_scopes = alloca (dpi.num_saved_scopes
+ * sizeof (*dpi.saved_scopes));
+ dpi.copy_templates = alloca (dpi.num_copy_templates
+ * sizeof (*dpi.copy_templates));
+#endif
+
+ d_print_comp (&dpi, options, dc);
+ }
+
+ d_print_flush (&dpi);
+
+ return ! d_print_saw_error (&dpi);
+}
+
+/* Turn components into a human readable string. OPTIONS is the
+ options bits passed to the demangler. DC is the tree to print.
+ ESTIMATE is a guess at the length of the result. This returns a
+ string allocated by malloc, or NULL on error. On success, this
+ sets *PALC to the size of the allocated buffer. On failure, this
+ sets *PALC to 0 for a bad parse, or to 1 for a memory allocation
+ failure. */
+
+CP_STATIC_IF_GLIBCPP_V3
+char *
+cplus_demangle_print (int options, const struct demangle_component *dc,
+ int estimate, size_t *palc)
+{
+ struct d_growable_string dgs;
+
+ d_growable_string_init (&dgs, estimate);
+
+ if (! cplus_demangle_print_callback (options, dc,
+ d_growable_string_callback_adapter,
+ &dgs))
+ {
+ free (dgs.buf);
+ *palc = 0;
+ return NULL;
+ }
+
+ *palc = dgs.allocation_failure ? 1 : dgs.alc;
+ return dgs.buf;
+}
+
+/* Returns the I'th element of the template arglist ARGS, or NULL on
+ failure. */
+
+static struct demangle_component *
+d_index_template_argument (struct demangle_component *args, int i)
+{
+ struct demangle_component *a;
+
+ for (a = args;
+ a != NULL;
+ a = d_right (a))
+ {
+ if (a->type != DEMANGLE_COMPONENT_TEMPLATE_ARGLIST)
+ return NULL;
+ if (i <= 0)
+ break;
+ --i;
+ }
+ if (i != 0 || a == NULL)
+ return NULL;
+
+ return d_left (a);
+}
+
+/* Returns the template argument from the current context indicated by DC,
+ which is a DEMANGLE_COMPONENT_TEMPLATE_PARAM, or NULL. */
+
+static struct demangle_component *
+d_lookup_template_argument (struct d_print_info *dpi,
+ const struct demangle_component *dc)
+{
+ if (dpi->templates == NULL)
+ {
+ d_print_error (dpi);
+ return NULL;
+ }
+
+ return d_index_template_argument
+ (d_right (dpi->templates->template_decl),
+ dc->u.s_number.number);
+}
+
+/* Returns a template argument pack used in DC (any will do), or NULL. */
+
+static struct demangle_component *
+d_find_pack (struct d_print_info *dpi,
+ const struct demangle_component *dc)
+{
+ struct demangle_component *a;
+ if (dc == NULL)
+ return NULL;
+
+ switch (dc->type)
+ {
+ case DEMANGLE_COMPONENT_TEMPLATE_PARAM:
+ a = d_lookup_template_argument (dpi, dc);
+ if (a && a->type == DEMANGLE_COMPONENT_TEMPLATE_ARGLIST)
+ return a;
+ return NULL;
+
+ case DEMANGLE_COMPONENT_PACK_EXPANSION:
+ return NULL;
+
+ case DEMANGLE_COMPONENT_LAMBDA:
+ case DEMANGLE_COMPONENT_NAME:
+ case DEMANGLE_COMPONENT_TAGGED_NAME:
+ case DEMANGLE_COMPONENT_OPERATOR:
+ case DEMANGLE_COMPONENT_BUILTIN_TYPE:
+ case DEMANGLE_COMPONENT_SUB_STD:
+ case DEMANGLE_COMPONENT_CHARACTER:
+ case DEMANGLE_COMPONENT_FUNCTION_PARAM:
+ case DEMANGLE_COMPONENT_UNNAMED_TYPE:
+ return NULL;
+
+ case DEMANGLE_COMPONENT_EXTENDED_OPERATOR:
+ return d_find_pack (dpi, dc->u.s_extended_operator.name);
+ case DEMANGLE_COMPONENT_CTOR:
+ return d_find_pack (dpi, dc->u.s_ctor.name);
+ case DEMANGLE_COMPONENT_DTOR:
+ return d_find_pack (dpi, dc->u.s_dtor.name);
+
+ default:
+ a = d_find_pack (dpi, d_left (dc));
+ if (a)
+ return a;
+ return d_find_pack (dpi, d_right (dc));
+ }
+}
+
+/* Returns the length of the template argument pack DC. */
+
+static int
+d_pack_length (const struct demangle_component *dc)
+{
+ int count = 0;
+ while (dc && dc->type == DEMANGLE_COMPONENT_TEMPLATE_ARGLIST
+ && d_left (dc) != NULL)
+ {
+ ++count;
+ dc = d_right (dc);
+ }
+ return count;
+}
+
+/* DC is a component of a mangled expression. Print it, wrapped in parens
+ if needed. */
+
+static void
+d_print_subexpr (struct d_print_info *dpi, int options,
+ const struct demangle_component *dc)
+{
+ int simple = 0;
+ if (dc->type == DEMANGLE_COMPONENT_NAME
+ || dc->type == DEMANGLE_COMPONENT_QUAL_NAME
+ || dc->type == DEMANGLE_COMPONENT_INITIALIZER_LIST
+ || dc->type == DEMANGLE_COMPONENT_FUNCTION_PARAM)
+ simple = 1;
+ if (!simple)
+ d_append_char (dpi, '(');
+ d_print_comp (dpi, options, dc);
+ if (!simple)
+ d_append_char (dpi, ')');
+}
+
+/* Save the current scope. */
+
+static void
+d_save_scope (struct d_print_info *dpi,
+ const struct demangle_component *container)
+{
+ struct d_saved_scope *scope;
+ struct d_print_template *src, **link;
+
+ if (dpi->next_saved_scope >= dpi->num_saved_scopes)
+ {
+ d_print_error (dpi);
+ return;
+ }
+ scope = &dpi->saved_scopes[dpi->next_saved_scope];
+ dpi->next_saved_scope++;
+
+ scope->container = container;
+ link = &scope->templates;
+
+ for (src = dpi->templates; src != NULL; src = src->next)
+ {
+ struct d_print_template *dst;
+
+ if (dpi->next_copy_template >= dpi->num_copy_templates)
+ {
+ d_print_error (dpi);
+ return;
+ }
+ dst = &dpi->copy_templates[dpi->next_copy_template];
+ dpi->next_copy_template++;
+
+ dst->template_decl = src->template_decl;
+ *link = dst;
+ link = &dst->next;
+ }
+
+ *link = NULL;
+}
+
+/* Attempt to locate a previously saved scope. Returns NULL if no
+ corresponding saved scope was found. */
+
+static struct d_saved_scope *
+d_get_saved_scope (struct d_print_info *dpi,
+ const struct demangle_component *container)
+{
+ int i;
+
+ for (i = 0; i < dpi->next_saved_scope; i++)
+ if (dpi->saved_scopes[i].container == container)
+ return &dpi->saved_scopes[i];
+
+ return NULL;
+}
+
+/* Subroutine to handle components. */
+
+static void
+d_print_comp (struct d_print_info *dpi, int options,
+ const struct demangle_component *dc)
+{
+ /* Magic variable to let reference smashing skip over the next modifier
+ without needing to modify *dc. */
+ const struct demangle_component *mod_inner = NULL;
+
+ /* Variable used to store the current templates while a previously
+ captured scope is used. */
+ struct d_print_template *saved_templates;
+
+ /* Nonzero if templates have been stored in the above variable. */
+ int need_template_restore = 0;
+
+ if (dc == NULL)
+ {
+ d_print_error (dpi);
+ return;
+ }
+ if (d_print_saw_error (dpi))
+ return;
+
+ switch (dc->type)
+ {
+ case DEMANGLE_COMPONENT_NAME:
+ if ((options & DMGL_JAVA) == 0)
+ d_append_buffer (dpi, dc->u.s_name.s, dc->u.s_name.len);
+ else
+ d_print_java_identifier (dpi, dc->u.s_name.s, dc->u.s_name.len);
+ return;
+
+ case DEMANGLE_COMPONENT_TAGGED_NAME:
+ d_print_comp (dpi, options, d_left (dc));
+ d_append_string (dpi, "[abi:");
+ d_print_comp (dpi, options, d_right (dc));
+ d_append_char (dpi, ']');
+ return;
+
+ case DEMANGLE_COMPONENT_QUAL_NAME:
+ case DEMANGLE_COMPONENT_LOCAL_NAME:
+ d_print_comp (dpi, options, d_left (dc));
+ if ((options & DMGL_JAVA) == 0)
+ d_append_string (dpi, "::");
+ else
+ d_append_char (dpi, '.');
+ {
+ struct demangle_component *local_name = d_right (dc);
+ if (local_name->type == DEMANGLE_COMPONENT_DEFAULT_ARG)
+ {
+ d_append_string (dpi, "{default arg#");
+ d_append_num (dpi, local_name->u.s_unary_num.num + 1);
+ d_append_string (dpi, "}::");
+ local_name = local_name->u.s_unary_num.sub;
+ }
+ d_print_comp (dpi, options, local_name);
+ }
+ return;
+
+ case DEMANGLE_COMPONENT_TYPED_NAME:
+ {
+ struct d_print_mod *hold_modifiers;
+ struct demangle_component *typed_name;
+ struct d_print_mod adpm[4];
+ unsigned int i;
+ struct d_print_template dpt;
+
+ /* Pass the name down to the type so that it can be printed in
+ the right place for the type. We also have to pass down
+ any CV-qualifiers, which apply to the this parameter. */
+ hold_modifiers = dpi->modifiers;
+ dpi->modifiers = 0;
+ i = 0;
+ typed_name = d_left (dc);
+ while (typed_name != NULL)
+ {
+ if (i >= sizeof adpm / sizeof adpm[0])
+ {
+ d_print_error (dpi);
+ return;
+ }
+
+ adpm[i].next = dpi->modifiers;
+ dpi->modifiers = &adpm[i];
+ adpm[i].mod = typed_name;
+ adpm[i].printed = 0;
+ adpm[i].templates = dpi->templates;
+ ++i;
+
+ if (typed_name->type != DEMANGLE_COMPONENT_RESTRICT_THIS
+ && typed_name->type != DEMANGLE_COMPONENT_VOLATILE_THIS
+ && typed_name->type != DEMANGLE_COMPONENT_CONST_THIS
+ && typed_name->type != DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS
+ && typed_name->type != DEMANGLE_COMPONENT_REFERENCE_THIS)
+ break;
+
+ typed_name = d_left (typed_name);
+ }
+
+ if (typed_name == NULL)
+ {
+ d_print_error (dpi);
+ return;
+ }
+
+ /* If typed_name is a template, then it applies to the
+ function type as well. */
+ if (typed_name->type == DEMANGLE_COMPONENT_TEMPLATE)
+ {
+ dpt.next = dpi->templates;
+ dpi->templates = &dpt;
+ dpt.template_decl = typed_name;
+ }
+
+ /* If typed_name is a DEMANGLE_COMPONENT_LOCAL_NAME, then
+ there may be CV-qualifiers on its right argument which
+ really apply here; this happens when parsing a class which
+ is local to a function. */
+ if (typed_name->type == DEMANGLE_COMPONENT_LOCAL_NAME)
+ {
+ struct demangle_component *local_name;
+
+ local_name = d_right (typed_name);
+ if (local_name->type == DEMANGLE_COMPONENT_DEFAULT_ARG)
+ local_name = local_name->u.s_unary_num.sub;
+ while (local_name->type == DEMANGLE_COMPONENT_RESTRICT_THIS
+ || local_name->type == DEMANGLE_COMPONENT_VOLATILE_THIS
+ || local_name->type == DEMANGLE_COMPONENT_CONST_THIS
+ || local_name->type == DEMANGLE_COMPONENT_REFERENCE_THIS
+ || (local_name->type
+ == DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS))
+ {
+ if (i >= sizeof adpm / sizeof adpm[0])
+ {
+ d_print_error (dpi);
+ return;
+ }
+
+ adpm[i] = adpm[i - 1];
+ adpm[i].next = &adpm[i - 1];
+ dpi->modifiers = &adpm[i];
+
+ adpm[i - 1].mod = local_name;
+ adpm[i - 1].printed = 0;
+ adpm[i - 1].templates = dpi->templates;
+ ++i;
+
+ local_name = d_left (local_name);
+ }
+ }
+
+ d_print_comp (dpi, options, d_right (dc));
+
+ if (typed_name->type == DEMANGLE_COMPONENT_TEMPLATE)
+ dpi->templates = dpt.next;
+
+ /* If the modifiers didn't get printed by the type, print them
+ now. */
+ while (i > 0)
+ {
+ --i;
+ if (! adpm[i].printed)
+ {
+ d_append_char (dpi, ' ');
+ d_print_mod (dpi, options, adpm[i].mod);
+ }
+ }
+
+ dpi->modifiers = hold_modifiers;
+
+ return;
+ }
+
+ case DEMANGLE_COMPONENT_TEMPLATE:
+ {
+ struct d_print_mod *hold_dpm;
+ struct demangle_component *dcl;
+ const struct demangle_component *hold_current;
+
+ /* This template may need to be referenced by a cast operator
+ contained in its subtree. */
+ hold_current = dpi->current_template;
+ dpi->current_template = dc;
+
+ /* Don't push modifiers into a template definition. Doing so
+ could give the wrong definition for a template argument.
+ Instead, treat the template essentially as a name. */
+
+ hold_dpm = dpi->modifiers;
+ dpi->modifiers = NULL;
+
+ dcl = d_left (dc);
+
+ if ((options & DMGL_JAVA) != 0
+ && dcl->type == DEMANGLE_COMPONENT_NAME
+ && dcl->u.s_name.len == 6
+ && strncmp (dcl->u.s_name.s, "JArray", 6) == 0)
+ {
+ /* Special-case Java arrays, so that JArray<TYPE> appears
+ instead as TYPE[]. */
+
+ d_print_comp (dpi, options, d_right (dc));
+ d_append_string (dpi, "[]");
+ }
+ else
+ {
+ d_print_comp (dpi, options, dcl);
+ if (d_last_char (dpi) == '<')
+ d_append_char (dpi, ' ');
+ d_append_char (dpi, '<');
+ d_print_comp (dpi, options, d_right (dc));
+ /* Avoid generating two consecutive '>' characters, to avoid
+ the C++ syntactic ambiguity. */
+ if (d_last_char (dpi) == '>')
+ d_append_char (dpi, ' ');
+ d_append_char (dpi, '>');
+ }
+
+ dpi->modifiers = hold_dpm;
+ dpi->current_template = hold_current;
+
+ return;
+ }
+
+ case DEMANGLE_COMPONENT_TEMPLATE_PARAM:
+ {
+ struct d_print_template *hold_dpt;
+ struct demangle_component *a = d_lookup_template_argument (dpi, dc);
+
+ if (a && a->type == DEMANGLE_COMPONENT_TEMPLATE_ARGLIST)
+ a = d_index_template_argument (a, dpi->pack_index);
+
+ if (a == NULL)
+ {
+ d_print_error (dpi);
+ return;
+ }
+
+ /* While processing this parameter, we need to pop the list of
+ templates. This is because the template parameter may
+ itself be a reference to a parameter of an outer
+ template. */
+
+ hold_dpt = dpi->templates;
+ dpi->templates = hold_dpt->next;
+
+ d_print_comp (dpi, options, a);
+
+ dpi->templates = hold_dpt;
+
+ return;
+ }
+
+ case DEMANGLE_COMPONENT_CTOR:
+ d_print_comp (dpi, options, dc->u.s_ctor.name);
+ return;
+
+ case DEMANGLE_COMPONENT_DTOR:
+ d_append_char (dpi, '~');
+ d_print_comp (dpi, options, dc->u.s_dtor.name);
+ return;
+
+ case DEMANGLE_COMPONENT_VTABLE:
+ d_append_string (dpi, "vtable for ");
+ d_print_comp (dpi, options, d_left (dc));
+ return;
+
+ case DEMANGLE_COMPONENT_VTT:
+ d_append_string (dpi, "VTT for ");
+ d_print_comp (dpi, options, d_left (dc));
+ return;
+
+ case DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE:
+ d_append_string (dpi, "construction vtable for ");
+ d_print_comp (dpi, options, d_left (dc));
+ d_append_string (dpi, "-in-");
+ d_print_comp (dpi, options, d_right (dc));
+ return;
+
+ case DEMANGLE_COMPONENT_TYPEINFO:
+ d_append_string (dpi, "typeinfo for ");
+ d_print_comp (dpi, options, d_left (dc));
+ return;
+
+ case DEMANGLE_COMPONENT_TYPEINFO_NAME:
+ d_append_string (dpi, "typeinfo name for ");
+ d_print_comp (dpi, options, d_left (dc));
+ return;
+
+ case DEMANGLE_COMPONENT_TYPEINFO_FN:
+ d_append_string (dpi, "typeinfo fn for ");
+ d_print_comp (dpi, options, d_left (dc));
+ return;
+
+ case DEMANGLE_COMPONENT_THUNK:
+ d_append_string (dpi, "non-virtual thunk to ");
+ d_print_comp (dpi, options, d_left (dc));
+ return;
+
+ case DEMANGLE_COMPONENT_VIRTUAL_THUNK:
+ d_append_string (dpi, "virtual thunk to ");
+ d_print_comp (dpi, options, d_left (dc));
+ return;
+
+ case DEMANGLE_COMPONENT_COVARIANT_THUNK:
+ d_append_string (dpi, "covariant return thunk to ");
+ d_print_comp (dpi, options, d_left (dc));
+ return;
+
+ case DEMANGLE_COMPONENT_JAVA_CLASS:
+ d_append_string (dpi, "java Class for ");
+ d_print_comp (dpi, options, d_left (dc));
+ return;
+
+ case DEMANGLE_COMPONENT_GUARD:
+ d_append_string (dpi, "guard variable for ");
+ d_print_comp (dpi, options, d_left (dc));
+ return;
+
+ case DEMANGLE_COMPONENT_TLS_INIT:
+ d_append_string (dpi, "TLS init function for ");
+ d_print_comp (dpi, options, d_left (dc));
+ return;
+
+ case DEMANGLE_COMPONENT_TLS_WRAPPER:
+ d_append_string (dpi, "TLS wrapper function for ");
+ d_print_comp (dpi, options, d_left (dc));
+ return;
+
+ case DEMANGLE_COMPONENT_REFTEMP:
+ d_append_string (dpi, "reference temporary #");
+ d_print_comp (dpi, options, d_right (dc));
+ d_append_string (dpi, " for ");
+ d_print_comp (dpi, options, d_left (dc));
+ return;
+
+ case DEMANGLE_COMPONENT_HIDDEN_ALIAS:
+ d_append_string (dpi, "hidden alias for ");
+ d_print_comp (dpi, options, d_left (dc));
+ return;
+
+ case DEMANGLE_COMPONENT_TRANSACTION_CLONE:
+ d_append_string (dpi, "transaction clone for ");
+ d_print_comp (dpi, options, d_left (dc));
+ return;
+
+ case DEMANGLE_COMPONENT_NONTRANSACTION_CLONE:
+ d_append_string (dpi, "non-transaction clone for ");
+ d_print_comp (dpi, options, d_left (dc));
+ return;
+
+ case DEMANGLE_COMPONENT_SUB_STD:
+ d_append_buffer (dpi, dc->u.s_string.string, dc->u.s_string.len);
+ return;
+
+ case DEMANGLE_COMPONENT_RESTRICT:
+ case DEMANGLE_COMPONENT_VOLATILE:
+ case DEMANGLE_COMPONENT_CONST:
+ {
+ struct d_print_mod *pdpm;
+
+ /* When printing arrays, it's possible to have cases where the
+ same CV-qualifier gets pushed on the stack multiple times.
+ We only need to print it once. */
+
+ for (pdpm = dpi->modifiers; pdpm != NULL; pdpm = pdpm->next)
+ {
+ if (! pdpm->printed)
+ {
+ if (pdpm->mod->type != DEMANGLE_COMPONENT_RESTRICT
+ && pdpm->mod->type != DEMANGLE_COMPONENT_VOLATILE
+ && pdpm->mod->type != DEMANGLE_COMPONENT_CONST)
+ break;
+ if (pdpm->mod->type == dc->type)
+ {
+ d_print_comp (dpi, options, d_left (dc));
+ return;
+ }
+ }
+ }
+ }
+ goto modifier;
+
+ case DEMANGLE_COMPONENT_REFERENCE:
+ case DEMANGLE_COMPONENT_RVALUE_REFERENCE:
+ {
+ /* Handle reference smashing: & + && = &. */
+ const struct demangle_component *sub = d_left (dc);
+ if (sub->type == DEMANGLE_COMPONENT_TEMPLATE_PARAM)
+ {
+ struct d_saved_scope *scope = d_get_saved_scope (dpi, sub);
+ struct demangle_component *a;
+
+ if (scope == NULL)
+ {
+ /* This is the first time SUB has been traversed.
+ We need to capture the current templates so
+ they can be restored if SUB is reentered as a
+ substitution. */
+ d_save_scope (dpi, sub);
+ if (d_print_saw_error (dpi))
+ return;
+ }
+ else
+ {
+ /* This traversal is reentering SUB as a substition.
+ Restore the original templates temporarily. */
+ saved_templates = dpi->templates;
+ dpi->templates = scope->templates;
+ need_template_restore = 1;
+ }
+
+ a = d_lookup_template_argument (dpi, sub);
+ if (a && a->type == DEMANGLE_COMPONENT_TEMPLATE_ARGLIST)
+ a = d_index_template_argument (a, dpi->pack_index);
+
+ if (a == NULL)
+ {
+ if (need_template_restore)
+ dpi->templates = saved_templates;
+
+ d_print_error (dpi);
+ return;
+ }
+
+ sub = a;
+ }
+
+ if (sub->type == DEMANGLE_COMPONENT_REFERENCE
+ || sub->type == dc->type)
+ dc = sub;
+ else if (sub->type == DEMANGLE_COMPONENT_RVALUE_REFERENCE)
+ mod_inner = d_left (sub);
+ }
+ /* Fall through. */
+
+ case DEMANGLE_COMPONENT_RESTRICT_THIS:
+ case DEMANGLE_COMPONENT_VOLATILE_THIS:
+ case DEMANGLE_COMPONENT_CONST_THIS:
+ case DEMANGLE_COMPONENT_REFERENCE_THIS:
+ case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS:
+ case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL:
+ case DEMANGLE_COMPONENT_POINTER:
+ case DEMANGLE_COMPONENT_COMPLEX:
+ case DEMANGLE_COMPONENT_IMAGINARY:
+ modifier:
+ {
+ /* We keep a list of modifiers on the stack. */
+ struct d_print_mod dpm;
+
+ dpm.next = dpi->modifiers;
+ dpi->modifiers = &dpm;
+ dpm.mod = dc;
+ dpm.printed = 0;
+ dpm.templates = dpi->templates;
+
+ if (!mod_inner)
+ mod_inner = d_left (dc);
+
+ d_print_comp (dpi, options, mod_inner);
+
+ /* If the modifier didn't get printed by the type, print it
+ now. */
+ if (! dpm.printed)
+ d_print_mod (dpi, options, dc);
+
+ dpi->modifiers = dpm.next;
+
+ if (need_template_restore)
+ dpi->templates = saved_templates;
+
+ return;
+ }
+
+ case DEMANGLE_COMPONENT_BUILTIN_TYPE:
+ if ((options & DMGL_JAVA) == 0)
+ d_append_buffer (dpi, dc->u.s_builtin.type->name,
+ dc->u.s_builtin.type->len);
+ else
+ d_append_buffer (dpi, dc->u.s_builtin.type->java_name,
+ dc->u.s_builtin.type->java_len);
+ return;
+
+ case DEMANGLE_COMPONENT_VENDOR_TYPE:
+ d_print_comp (dpi, options, d_left (dc));
+ return;
+
+ case DEMANGLE_COMPONENT_FUNCTION_TYPE:
+ {
+ if ((options & DMGL_RET_POSTFIX) != 0)
+ d_print_function_type (dpi,
+ options & ~(DMGL_RET_POSTFIX | DMGL_RET_DROP),
+ dc, dpi->modifiers);
+
+ /* Print return type if present */
+ if (d_left (dc) != NULL && (options & DMGL_RET_POSTFIX) != 0)
+ d_print_comp (dpi, options & ~(DMGL_RET_POSTFIX | DMGL_RET_DROP),
+ d_left (dc));
+ else if (d_left (dc) != NULL && (options & DMGL_RET_DROP) == 0)
+ {
+ struct d_print_mod dpm;
+
+ /* We must pass this type down as a modifier in order to
+ print it in the right location. */
+ dpm.next = dpi->modifiers;
+ dpi->modifiers = &dpm;
+ dpm.mod = dc;
+ dpm.printed = 0;
+ dpm.templates = dpi->templates;
+
+ d_print_comp (dpi, options & ~(DMGL_RET_POSTFIX | DMGL_RET_DROP),
+ d_left (dc));
+
+ dpi->modifiers = dpm.next;
+
+ if (dpm.printed)
+ return;
+
+ /* In standard prefix notation, there is a space between the
+ return type and the function signature. */
+ if ((options & DMGL_RET_POSTFIX) == 0)
+ d_append_char (dpi, ' ');
+ }
+
+ if ((options & DMGL_RET_POSTFIX) == 0)
+ d_print_function_type (dpi,
+ options & ~(DMGL_RET_POSTFIX | DMGL_RET_DROP),
+ dc, dpi->modifiers);
+
+ return;
+ }
+
+ case DEMANGLE_COMPONENT_ARRAY_TYPE:
+ {
+ struct d_print_mod *hold_modifiers;
+ struct d_print_mod adpm[4];
+ unsigned int i;
+ struct d_print_mod *pdpm;
+
+ /* We must pass this type down as a modifier in order to print
+ multi-dimensional arrays correctly. If the array itself is
+ CV-qualified, we act as though the element type were
+ CV-qualified. We do this by copying the modifiers down
+ rather than fiddling pointers, so that we don't wind up
+ with a d_print_mod higher on the stack pointing into our
+ stack frame after we return. */
+
+ hold_modifiers = dpi->modifiers;
+
+ adpm[0].next = hold_modifiers;
+ dpi->modifiers = &adpm[0];
+ adpm[0].mod = dc;
+ adpm[0].printed = 0;
+ adpm[0].templates = dpi->templates;
+
+ i = 1;
+ pdpm = hold_modifiers;
+ while (pdpm != NULL
+ && (pdpm->mod->type == DEMANGLE_COMPONENT_RESTRICT
+ || pdpm->mod->type == DEMANGLE_COMPONENT_VOLATILE
+ || pdpm->mod->type == DEMANGLE_COMPONENT_CONST))
+ {
+ if (! pdpm->printed)
+ {
+ if (i >= sizeof adpm / sizeof adpm[0])
+ {
+ d_print_error (dpi);
+ return;
+ }
+
+ adpm[i] = *pdpm;
+ adpm[i].next = dpi->modifiers;
+ dpi->modifiers = &adpm[i];
+ pdpm->printed = 1;
+ ++i;
+ }
+
+ pdpm = pdpm->next;
+ }
+
+ d_print_comp (dpi, options, d_right (dc));
+
+ dpi->modifiers = hold_modifiers;
+
+ if (adpm[0].printed)
+ return;
+
+ while (i > 1)
+ {
+ --i;
+ d_print_mod (dpi, options, adpm[i].mod);
+ }
+
+ d_print_array_type (dpi, options, dc, dpi->modifiers);
+
+ return;
+ }
+
+ case DEMANGLE_COMPONENT_PTRMEM_TYPE:
+ case DEMANGLE_COMPONENT_VECTOR_TYPE:
+ {
+ struct d_print_mod dpm;
+
+ dpm.next = dpi->modifiers;
+ dpi->modifiers = &dpm;
+ dpm.mod = dc;
+ dpm.printed = 0;
+ dpm.templates = dpi->templates;
+
+ d_print_comp (dpi, options, d_right (dc));
+
+ /* If the modifier didn't get printed by the type, print it
+ now. */
+ if (! dpm.printed)
+ d_print_mod (dpi, options, dc);
+
+ dpi->modifiers = dpm.next;
+
+ return;
+ }
+
+ case DEMANGLE_COMPONENT_FIXED_TYPE:
+ if (dc->u.s_fixed.sat)
+ d_append_string (dpi, "_Sat ");
+ /* Don't print "int _Accum". */
+ if (dc->u.s_fixed.length->u.s_builtin.type
+ != &cplus_demangle_builtin_types['i'-'a'])
+ {
+ d_print_comp (dpi, options, dc->u.s_fixed.length);
+ d_append_char (dpi, ' ');
+ }
+ if (dc->u.s_fixed.accum)
+ d_append_string (dpi, "_Accum");
+ else
+ d_append_string (dpi, "_Fract");
+ return;
+
+ case DEMANGLE_COMPONENT_ARGLIST:
+ case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST:
+ if (d_left (dc) != NULL)
+ d_print_comp (dpi, options, d_left (dc));
+ if (d_right (dc) != NULL)
+ {
+ size_t len;
+ unsigned long int flush_count;
+ /* Make sure ", " isn't flushed by d_append_string, otherwise
+ dpi->len -= 2 wouldn't work. */
+ if (dpi->len >= sizeof (dpi->buf) - 2)
+ d_print_flush (dpi);
+ d_append_string (dpi, ", ");
+ len = dpi->len;
+ flush_count = dpi->flush_count;
+ d_print_comp (dpi, options, d_right (dc));
+ /* If that didn't print anything (which can happen with empty
+ template argument packs), remove the comma and space. */
+ if (dpi->flush_count == flush_count && dpi->len == len)
+ dpi->len -= 2;
+ }
+ return;
+
+ case DEMANGLE_COMPONENT_INITIALIZER_LIST:
+ {
+ struct demangle_component *type = d_left (dc);
+ struct demangle_component *list = d_right (dc);
+
+ if (type)
+ d_print_comp (dpi, options, type);
+ d_append_char (dpi, '{');
+ d_print_comp (dpi, options, list);
+ d_append_char (dpi, '}');
+ }
+ return;
+
+ case DEMANGLE_COMPONENT_OPERATOR:
+ {
+ const struct demangle_operator_info *op = dc->u.s_operator.op;
+ int len = op->len;
+
+ d_append_string (dpi, "operator");
+ /* Add a space before new/delete. */
+ if (IS_LOWER (op->name[0]))
+ d_append_char (dpi, ' ');
+ /* Omit a trailing space. */
+ if (op->name[len-1] == ' ')
+ --len;
+ d_append_buffer (dpi, op->name, len);
+ return;
+ }
+
+ case DEMANGLE_COMPONENT_EXTENDED_OPERATOR:
+ d_append_string (dpi, "operator ");
+ d_print_comp (dpi, options, dc->u.s_extended_operator.name);
+ return;
+
+ case DEMANGLE_COMPONENT_CAST:
+ d_append_string (dpi, "operator ");
+ d_print_cast (dpi, options, dc);
+ return;
+
+ case DEMANGLE_COMPONENT_NULLARY:
+ d_print_expr_op (dpi, options, d_left (dc));
+ return;
+
+ case DEMANGLE_COMPONENT_UNARY:
+ {
+ struct demangle_component *op = d_left (dc);
+ struct demangle_component *operand = d_right (dc);
+ const char *code = NULL;
+
+ if (op->type == DEMANGLE_COMPONENT_OPERATOR)
+ {
+ code = op->u.s_operator.op->code;
+ if (!strcmp (code, "ad"))
+ {
+ /* Don't print the argument list for the address of a
+ function. */
+ if (operand->type == DEMANGLE_COMPONENT_TYPED_NAME
+ && d_left (operand)->type == DEMANGLE_COMPONENT_QUAL_NAME
+ && d_right (operand)->type == DEMANGLE_COMPONENT_FUNCTION_TYPE)
+ operand = d_left (operand);
+ }
+ if (operand->type == DEMANGLE_COMPONENT_BINARY_ARGS)
+ {
+ /* This indicates a suffix operator. */
+ operand = d_left (operand);
+ d_print_subexpr (dpi, options, operand);
+ d_print_expr_op (dpi, options, op);
+ return;
+ }
+ }
+
+ if (op->type != DEMANGLE_COMPONENT_CAST)
+ d_print_expr_op (dpi, options, op);
+ else
+ {
+ d_append_char (dpi, '(');
+ d_print_cast (dpi, options, op);
+ d_append_char (dpi, ')');
+ }
+ if (code && !strcmp (code, "gs"))
+ /* Avoid parens after '::'. */
+ d_print_comp (dpi, options, operand);
+ else if (code && !strcmp (code, "st"))
+ /* Always print parens for sizeof (type). */
+ {
+ d_append_char (dpi, '(');
+ d_print_comp (dpi, options, operand);
+ d_append_char (dpi, ')');
+ }
+ else
+ d_print_subexpr (dpi, options, operand);
+ }
+ return;
+
+ case DEMANGLE_COMPONENT_BINARY:
+ if (d_right (dc)->type != DEMANGLE_COMPONENT_BINARY_ARGS)
+ {
+ d_print_error (dpi);
+ return;
+ }
+
+ if (op_is_new_cast (d_left (dc)))
+ {
+ d_print_expr_op (dpi, options, d_left (dc));
+ d_append_char (dpi, '<');
+ d_print_comp (dpi, options, d_left (d_right (dc)));
+ d_append_string (dpi, ">(");
+ d_print_comp (dpi, options, d_right (d_right (dc)));
+ d_append_char (dpi, ')');
+ return;
+ }
+
+ /* We wrap an expression which uses the greater-than operator in
+ an extra layer of parens so that it does not get confused
+ with the '>' which ends the template parameters. */
+ if (d_left (dc)->type == DEMANGLE_COMPONENT_OPERATOR
+ && d_left (dc)->u.s_operator.op->len == 1
+ && d_left (dc)->u.s_operator.op->name[0] == '>')
+ d_append_char (dpi, '(');
+
+ if (strcmp (d_left (dc)->u.s_operator.op->code, "cl") == 0
+ && d_left (d_right (dc))->type == DEMANGLE_COMPONENT_TYPED_NAME)
+ {
+ /* Function call used in an expression should not have printed types
+ of the function arguments. Values of the function arguments still
+ get printed below. */
+
+ const struct demangle_component *func = d_left (d_right (dc));
+
+ if (d_right (func)->type != DEMANGLE_COMPONENT_FUNCTION_TYPE)
+ d_print_error (dpi);
+ d_print_subexpr (dpi, options, d_left (func));
+ }
+ else
+ d_print_subexpr (dpi, options, d_left (d_right (dc)));
+ if (strcmp (d_left (dc)->u.s_operator.op->code, "ix") == 0)
+ {
+ d_append_char (dpi, '[');
+ d_print_comp (dpi, options, d_right (d_right (dc)));
+ d_append_char (dpi, ']');
+ }
+ else
+ {
+ if (strcmp (d_left (dc)->u.s_operator.op->code, "cl") != 0)
+ d_print_expr_op (dpi, options, d_left (dc));
+ d_print_subexpr (dpi, options, d_right (d_right (dc)));
+ }
+
+ if (d_left (dc)->type == DEMANGLE_COMPONENT_OPERATOR
+ && d_left (dc)->u.s_operator.op->len == 1
+ && d_left (dc)->u.s_operator.op->name[0] == '>')
+ d_append_char (dpi, ')');
+
+ return;
+
+ case DEMANGLE_COMPONENT_BINARY_ARGS:
+ /* We should only see this as part of DEMANGLE_COMPONENT_BINARY. */
+ d_print_error (dpi);
+ return;
+
+ case DEMANGLE_COMPONENT_TRINARY:
+ if (d_right (dc)->type != DEMANGLE_COMPONENT_TRINARY_ARG1
+ || d_right (d_right (dc))->type != DEMANGLE_COMPONENT_TRINARY_ARG2)
+ {
+ d_print_error (dpi);
+ return;
+ }
+ {
+ struct demangle_component *op = d_left (dc);
+ struct demangle_component *first = d_left (d_right (dc));
+ struct demangle_component *second = d_left (d_right (d_right (dc)));
+ struct demangle_component *third = d_right (d_right (d_right (dc)));
+
+ if (!strcmp (op->u.s_operator.op->code, "qu"))
+ {
+ d_print_subexpr (dpi, options, first);
+ d_print_expr_op (dpi, options, op);
+ d_print_subexpr (dpi, options, second);
+ d_append_string (dpi, " : ");
+ d_print_subexpr (dpi, options, third);
+ }
+ else
+ {
+ d_append_string (dpi, "new ");
+ if (d_left (first) != NULL)
+ {
+ d_print_subexpr (dpi, options, first);
+ d_append_char (dpi, ' ');
+ }
+ d_print_comp (dpi, options, second);
+ if (third)
+ d_print_subexpr (dpi, options, third);
+ }
+ }
+ return;
+
+ case DEMANGLE_COMPONENT_TRINARY_ARG1:
+ case DEMANGLE_COMPONENT_TRINARY_ARG2:
+ /* We should only see these are part of DEMANGLE_COMPONENT_TRINARY. */
+ d_print_error (dpi);
+ return;
+
+ case DEMANGLE_COMPONENT_LITERAL:
+ case DEMANGLE_COMPONENT_LITERAL_NEG:
+ {
+ enum d_builtin_type_print tp;
+
+ /* For some builtin types, produce simpler output. */
+ tp = D_PRINT_DEFAULT;
+ if (d_left (dc)->type == DEMANGLE_COMPONENT_BUILTIN_TYPE)
+ {
+ tp = d_left (dc)->u.s_builtin.type->print;
+ switch (tp)
+ {
+ case D_PRINT_INT:
+ case D_PRINT_UNSIGNED:
+ case D_PRINT_LONG:
+ case D_PRINT_UNSIGNED_LONG:
+ case D_PRINT_LONG_LONG:
+ case D_PRINT_UNSIGNED_LONG_LONG:
+ if (d_right (dc)->type == DEMANGLE_COMPONENT_NAME)
+ {
+ if (dc->type == DEMANGLE_COMPONENT_LITERAL_NEG)
+ d_append_char (dpi, '-');
+ d_print_comp (dpi, options, d_right (dc));
+ switch (tp)
+ {
+ default:
+ break;
+ case D_PRINT_UNSIGNED:
+ d_append_char (dpi, 'u');
+ break;
+ case D_PRINT_LONG:
+ d_append_char (dpi, 'l');
+ break;
+ case D_PRINT_UNSIGNED_LONG:
+ d_append_string (dpi, "ul");
+ break;
+ case D_PRINT_LONG_LONG:
+ d_append_string (dpi, "ll");
+ break;
+ case D_PRINT_UNSIGNED_LONG_LONG:
+ d_append_string (dpi, "ull");
+ break;
+ }
+ return;
+ }
+ break;
+
+ case D_PRINT_BOOL:
+ if (d_right (dc)->type == DEMANGLE_COMPONENT_NAME
+ && d_right (dc)->u.s_name.len == 1
+ && dc->type == DEMANGLE_COMPONENT_LITERAL)
+ {
+ switch (d_right (dc)->u.s_name.s[0])
+ {
+ case '0':
+ d_append_string (dpi, "false");
+ return;
+ case '1':
+ d_append_string (dpi, "true");
+ return;
+ default:
+ break;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ d_append_char (dpi, '(');
+ d_print_comp (dpi, options, d_left (dc));
+ d_append_char (dpi, ')');
+ if (dc->type == DEMANGLE_COMPONENT_LITERAL_NEG)
+ d_append_char (dpi, '-');
+ if (tp == D_PRINT_FLOAT)
+ d_append_char (dpi, '[');
+ d_print_comp (dpi, options, d_right (dc));
+ if (tp == D_PRINT_FLOAT)
+ d_append_char (dpi, ']');
+ }
+ return;
+
+ case DEMANGLE_COMPONENT_NUMBER:
+ d_append_num (dpi, dc->u.s_number.number);
+ return;
+
+ case DEMANGLE_COMPONENT_JAVA_RESOURCE:
+ d_append_string (dpi, "java resource ");
+ d_print_comp (dpi, options, d_left (dc));
+ return;
+
+ case DEMANGLE_COMPONENT_COMPOUND_NAME:
+ d_print_comp (dpi, options, d_left (dc));
+ d_print_comp (dpi, options, d_right (dc));
+ return;
+
+ case DEMANGLE_COMPONENT_CHARACTER:
+ d_append_char (dpi, dc->u.s_character.character);
+ return;
+
+ case DEMANGLE_COMPONENT_DECLTYPE:
+ d_append_string (dpi, "decltype (");
+ d_print_comp (dpi, options, d_left (dc));
+ d_append_char (dpi, ')');
+ return;
+
+ case DEMANGLE_COMPONENT_PACK_EXPANSION:
+ {
+ int len;
+ int i;
+ struct demangle_component *a = d_find_pack (dpi, d_left (dc));
+ if (a == NULL)
+ {
+ /* d_find_pack won't find anything if the only packs involved
+ in this expansion are function parameter packs; in that
+ case, just print the pattern and "...". */
+ d_print_subexpr (dpi, options, d_left (dc));
+ d_append_string (dpi, "...");
+ return;
+ }
+
+ len = d_pack_length (a);
+ dc = d_left (dc);
+ for (i = 0; i < len; ++i)
+ {
+ dpi->pack_index = i;
+ d_print_comp (dpi, options, dc);
+ if (i < len-1)
+ d_append_string (dpi, ", ");
+ }
+ }
+ return;
+
+ case DEMANGLE_COMPONENT_FUNCTION_PARAM:
+ {
+ long num = dc->u.s_number.number;
+ if (num == 0)
+ d_append_string (dpi, "this");
+ else
+ {
+ d_append_string (dpi, "{parm#");
+ d_append_num (dpi, num);
+ d_append_char (dpi, '}');
+ }
+ }
+ return;
+
+ case DEMANGLE_COMPONENT_GLOBAL_CONSTRUCTORS:
+ d_append_string (dpi, "global constructors keyed to ");
+ d_print_comp (dpi, options, dc->u.s_binary.left);
+ return;
+
+ case DEMANGLE_COMPONENT_GLOBAL_DESTRUCTORS:
+ d_append_string (dpi, "global destructors keyed to ");
+ d_print_comp (dpi, options, dc->u.s_binary.left);
+ return;
+
+ case DEMANGLE_COMPONENT_LAMBDA:
+ d_append_string (dpi, "{lambda(");
+ d_print_comp (dpi, options, dc->u.s_unary_num.sub);
+ d_append_string (dpi, ")#");
+ d_append_num (dpi, dc->u.s_unary_num.num + 1);
+ d_append_char (dpi, '}');
+ return;
+
+ case DEMANGLE_COMPONENT_UNNAMED_TYPE:
+ d_append_string (dpi, "{unnamed type#");
+ d_append_num (dpi, dc->u.s_number.number + 1);
+ d_append_char (dpi, '}');
+ return;
+
+ case DEMANGLE_COMPONENT_CLONE:
+ d_print_comp (dpi, options, d_left (dc));
+ d_append_string (dpi, " [clone ");
+ d_print_comp (dpi, options, d_right (dc));
+ d_append_char (dpi, ']');
+ return;
+
+ default:
+ d_print_error (dpi);
+ return;
+ }
+}
+
+/* Print a Java dentifier. For Java we try to handle encoded extended
+ Unicode characters. The C++ ABI doesn't mention Unicode encoding,
+ so we don't it for C++. Characters are encoded as
+ __U<hex-char>+_. */
+
+static void
+d_print_java_identifier (struct d_print_info *dpi, const char *name, int len)
+{
+ const char *p;
+ const char *end;
+
+ end = name + len;
+ for (p = name; p < end; ++p)
+ {
+ if (end - p > 3
+ && p[0] == '_'
+ && p[1] == '_'
+ && p[2] == 'U')
+ {
+ unsigned long c;
+ const char *q;
+
+ c = 0;
+ for (q = p + 3; q < end; ++q)
+ {
+ int dig;
+
+ if (IS_DIGIT (*q))
+ dig = *q - '0';
+ else if (*q >= 'A' && *q <= 'F')
+ dig = *q - 'A' + 10;
+ else if (*q >= 'a' && *q <= 'f')
+ dig = *q - 'a' + 10;
+ else
+ break;
+
+ c = c * 16 + dig;
+ }
+ /* If the Unicode character is larger than 256, we don't try
+ to deal with it here. FIXME. */
+ if (q < end && *q == '_' && c < 256)
+ {
+ d_append_char (dpi, c);
+ p = q;
+ continue;
+ }
+ }
+
+ d_append_char (dpi, *p);
+ }
+}
+
+/* Print a list of modifiers. SUFFIX is 1 if we are printing
+ qualifiers on this after printing a function. */
+
+static void
+d_print_mod_list (struct d_print_info *dpi, int options,
+ struct d_print_mod *mods, int suffix)
+{
+ struct d_print_template *hold_dpt;
+
+ if (mods == NULL || d_print_saw_error (dpi))
+ return;
+
+ if (mods->printed
+ || (! suffix
+ && (mods->mod->type == DEMANGLE_COMPONENT_RESTRICT_THIS
+ || mods->mod->type == DEMANGLE_COMPONENT_VOLATILE_THIS
+ || mods->mod->type == DEMANGLE_COMPONENT_CONST_THIS
+ || mods->mod->type == DEMANGLE_COMPONENT_REFERENCE_THIS
+ || (mods->mod->type
+ == DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS))))
+ {
+ d_print_mod_list (dpi, options, mods->next, suffix);
+ return;
+ }
+
+ mods->printed = 1;
+
+ hold_dpt = dpi->templates;
+ dpi->templates = mods->templates;
+
+ if (mods->mod->type == DEMANGLE_COMPONENT_FUNCTION_TYPE)
+ {
+ d_print_function_type (dpi, options, mods->mod, mods->next);
+ dpi->templates = hold_dpt;
+ return;
+ }
+ else if (mods->mod->type == DEMANGLE_COMPONENT_ARRAY_TYPE)
+ {
+ d_print_array_type (dpi, options, mods->mod, mods->next);
+ dpi->templates = hold_dpt;
+ return;
+ }
+ else if (mods->mod->type == DEMANGLE_COMPONENT_LOCAL_NAME)
+ {
+ struct d_print_mod *hold_modifiers;
+ struct demangle_component *dc;
+
+ /* When this is on the modifier stack, we have pulled any
+ qualifiers off the right argument already. Otherwise, we
+ print it as usual, but don't let the left argument see any
+ modifiers. */
+
+ hold_modifiers = dpi->modifiers;
+ dpi->modifiers = NULL;
+ d_print_comp (dpi, options, d_left (mods->mod));
+ dpi->modifiers = hold_modifiers;
+
+ if ((options & DMGL_JAVA) == 0)
+ d_append_string (dpi, "::");
+ else
+ d_append_char (dpi, '.');
+
+ dc = d_right (mods->mod);
+
+ if (dc->type == DEMANGLE_COMPONENT_DEFAULT_ARG)
+ {
+ d_append_string (dpi, "{default arg#");
+ d_append_num (dpi, dc->u.s_unary_num.num + 1);
+ d_append_string (dpi, "}::");
+ dc = dc->u.s_unary_num.sub;
+ }
+
+ while (dc->type == DEMANGLE_COMPONENT_RESTRICT_THIS
+ || dc->type == DEMANGLE_COMPONENT_VOLATILE_THIS
+ || dc->type == DEMANGLE_COMPONENT_CONST_THIS
+ || dc->type == DEMANGLE_COMPONENT_REFERENCE_THIS
+ || dc->type == DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS)
+ dc = d_left (dc);
+
+ d_print_comp (dpi, options, dc);
+
+ dpi->templates = hold_dpt;
+ return;
+ }
+
+ d_print_mod (dpi, options, mods->mod);
+
+ dpi->templates = hold_dpt;
+
+ d_print_mod_list (dpi, options, mods->next, suffix);
+}
+
+/* Print a modifier. */
+
+static void
+d_print_mod (struct d_print_info *dpi, int options,
+ const struct demangle_component *mod)
+{
+ switch (mod->type)
+ {
+ case DEMANGLE_COMPONENT_RESTRICT:
+ case DEMANGLE_COMPONENT_RESTRICT_THIS:
+ d_append_string (dpi, " restrict");
+ return;
+ case DEMANGLE_COMPONENT_VOLATILE:
+ case DEMANGLE_COMPONENT_VOLATILE_THIS:
+ d_append_string (dpi, " volatile");
+ return;
+ case DEMANGLE_COMPONENT_CONST:
+ case DEMANGLE_COMPONENT_CONST_THIS:
+ d_append_string (dpi, " const");
+ return;
+ case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL:
+ d_append_char (dpi, ' ');
+ d_print_comp (dpi, options, d_right (mod));
+ return;
+ case DEMANGLE_COMPONENT_POINTER:
+ /* There is no pointer symbol in Java. */
+ if ((options & DMGL_JAVA) == 0)
+ d_append_char (dpi, '*');
+ return;
+ case DEMANGLE_COMPONENT_REFERENCE_THIS:
+ /* For the ref-qualifier, put a space before the &. */
+ d_append_char (dpi, ' ');
+ case DEMANGLE_COMPONENT_REFERENCE:
+ d_append_char (dpi, '&');
+ return;
+ case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS:
+ d_append_char (dpi, ' ');
+ case DEMANGLE_COMPONENT_RVALUE_REFERENCE:
+ d_append_string (dpi, "&&");
+ return;
+ case DEMANGLE_COMPONENT_COMPLEX:
+ d_append_string (dpi, "complex ");
+ return;
+ case DEMANGLE_COMPONENT_IMAGINARY:
+ d_append_string (dpi, "imaginary ");
+ return;
+ case DEMANGLE_COMPONENT_PTRMEM_TYPE:
+ if (d_last_char (dpi) != '(')
+ d_append_char (dpi, ' ');
+ d_print_comp (dpi, options, d_left (mod));
+ d_append_string (dpi, "::*");
+ return;
+ case DEMANGLE_COMPONENT_TYPED_NAME:
+ d_print_comp (dpi, options, d_left (mod));
+ return;
+ case DEMANGLE_COMPONENT_VECTOR_TYPE:
+ d_append_string (dpi, " __vector(");
+ d_print_comp (dpi, options, d_left (mod));
+ d_append_char (dpi, ')');
+ return;
+
+ default:
+ /* Otherwise, we have something that won't go back on the
+ modifier stack, so we can just print it. */
+ d_print_comp (dpi, options, mod);
+ return;
+ }
+}
+
+/* Print a function type, except for the return type. */
+
+static void
+d_print_function_type (struct d_print_info *dpi, int options,
+ const struct demangle_component *dc,
+ struct d_print_mod *mods)
+{
+ int need_paren;
+ int need_space;
+ struct d_print_mod *p;
+ struct d_print_mod *hold_modifiers;
+
+ need_paren = 0;
+ need_space = 0;
+ for (p = mods; p != NULL; p = p->next)
+ {
+ if (p->printed)
+ break;
+
+ switch (p->mod->type)
+ {
+ case DEMANGLE_COMPONENT_POINTER:
+ case DEMANGLE_COMPONENT_REFERENCE:
+ case DEMANGLE_COMPONENT_RVALUE_REFERENCE:
+ need_paren = 1;
+ break;
+ case DEMANGLE_COMPONENT_RESTRICT:
+ case DEMANGLE_COMPONENT_VOLATILE:
+ case DEMANGLE_COMPONENT_CONST:
+ case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL:
+ case DEMANGLE_COMPONENT_COMPLEX:
+ case DEMANGLE_COMPONENT_IMAGINARY:
+ case DEMANGLE_COMPONENT_PTRMEM_TYPE:
+ need_space = 1;
+ need_paren = 1;
+ break;
+ case DEMANGLE_COMPONENT_RESTRICT_THIS:
+ case DEMANGLE_COMPONENT_VOLATILE_THIS:
+ case DEMANGLE_COMPONENT_CONST_THIS:
+ case DEMANGLE_COMPONENT_REFERENCE_THIS:
+ case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS:
+ break;
+ default:
+ break;
+ }
+ if (need_paren)
+ break;
+ }
+
+ if (need_paren)
+ {
+ if (! need_space)
+ {
+ if (d_last_char (dpi) != '('
+ && d_last_char (dpi) != '*')
+ need_space = 1;
+ }
+ if (need_space && d_last_char (dpi) != ' ')
+ d_append_char (dpi, ' ');
+ d_append_char (dpi, '(');
+ }
+
+ hold_modifiers = dpi->modifiers;
+ dpi->modifiers = NULL;
+
+ d_print_mod_list (dpi, options, mods, 0);
+
+ if (need_paren)
+ d_append_char (dpi, ')');
+
+ d_append_char (dpi, '(');
+
+ if (d_right (dc) != NULL)
+ d_print_comp (dpi, options, d_right (dc));
+
+ d_append_char (dpi, ')');
+
+ d_print_mod_list (dpi, options, mods, 1);
+
+ dpi->modifiers = hold_modifiers;
+}
+
+/* Print an array type, except for the element type. */
+
+static void
+d_print_array_type (struct d_print_info *dpi, int options,
+ const struct demangle_component *dc,
+ struct d_print_mod *mods)
+{
+ int need_space;
+
+ need_space = 1;
+ if (mods != NULL)
+ {
+ int need_paren;
+ struct d_print_mod *p;
+
+ need_paren = 0;
+ for (p = mods; p != NULL; p = p->next)
+ {
+ if (! p->printed)
+ {
+ if (p->mod->type == DEMANGLE_COMPONENT_ARRAY_TYPE)
+ {
+ need_space = 0;
+ break;
+ }
+ else
+ {
+ need_paren = 1;
+ need_space = 1;
+ break;
+ }
+ }
+ }
+
+ if (need_paren)
+ d_append_string (dpi, " (");
+
+ d_print_mod_list (dpi, options, mods, 0);
+
+ if (need_paren)
+ d_append_char (dpi, ')');
+ }
+
+ if (need_space)
+ d_append_char (dpi, ' ');
+
+ d_append_char (dpi, '[');
+
+ if (d_left (dc) != NULL)
+ d_print_comp (dpi, options, d_left (dc));
+
+ d_append_char (dpi, ']');
+}
+
+/* Print an operator in an expression. */
+
+static void
+d_print_expr_op (struct d_print_info *dpi, int options,
+ const struct demangle_component *dc)
+{
+ if (dc->type == DEMANGLE_COMPONENT_OPERATOR)
+ d_append_buffer (dpi, dc->u.s_operator.op->name,
+ dc->u.s_operator.op->len);
+ else
+ d_print_comp (dpi, options, dc);
+}
+
+/* Print a cast. */
+
+static void
+d_print_cast (struct d_print_info *dpi, int options,
+ const struct demangle_component *dc)
+{
+ struct d_print_template dpt;
+
+ /* For a cast operator, we need the template parameters from
+ the enclosing template in scope for processing the type. */
+ if (dpi->current_template != NULL)
+ {
+ dpt.next = dpi->templates;
+ dpi->templates = &dpt;
+ dpt.template_decl = dpi->current_template;
+ }
+
+ if (d_left (dc)->type != DEMANGLE_COMPONENT_TEMPLATE)
+ {
+ d_print_comp (dpi, options, d_left (dc));
+ if (dpi->current_template != NULL)
+ dpi->templates = dpt.next;
+ }
+ else
+ {
+ d_print_comp (dpi, options, d_left (d_left (dc)));
+
+ /* For a templated cast operator, we need to remove the template
+ parameters from scope after printing the operator name,
+ so we need to handle the template printing here. */
+ if (dpi->current_template != NULL)
+ dpi->templates = dpt.next;
+
+ if (d_last_char (dpi) == '<')
+ d_append_char (dpi, ' ');
+ d_append_char (dpi, '<');
+ d_print_comp (dpi, options, d_right (d_left (dc)));
+ /* Avoid generating two consecutive '>' characters, to avoid
+ the C++ syntactic ambiguity. */
+ if (d_last_char (dpi) == '>')
+ d_append_char (dpi, ' ');
+ d_append_char (dpi, '>');
+ }
+}
+
+/* Initialize the information structure we use to pass around
+ information. */
+
+CP_STATIC_IF_GLIBCPP_V3
+void
+cplus_demangle_init_info (const char *mangled, int options, size_t len,
+ struct d_info *di)
+{
+ di->s = mangled;
+ di->send = mangled + len;
+ di->options = options;
+
+ di->n = mangled;
+
+ /* We can not need more components than twice the number of chars in
+ the mangled string. Most components correspond directly to
+ chars, but the ARGLIST types are exceptions. */
+ di->num_comps = 2 * len;
+ di->next_comp = 0;
+
+ /* Similarly, we can not need more substitutions than there are
+ chars in the mangled string. */
+ di->num_subs = len;
+ di->next_sub = 0;
+ di->did_subs = 0;
+
+ di->last_name = NULL;
+
+ di->expansion = 0;
+ di->is_expression = 0;
+ di->is_conversion = 0;
+}
+
+/* Internal implementation for the demangler. If MANGLED is a g++ v3 ABI
+ mangled name, return strings in repeated callback giving the demangled
+ name. OPTIONS is the usual libiberty demangler options. On success,
+ this returns 1. On failure, returns 0. */
+
+static int
+d_demangle_callback (const char *mangled, int options,
+ demangle_callbackref callback, void *opaque)
+{
+ enum
+ {
+ DCT_TYPE,
+ DCT_MANGLED,
+ DCT_GLOBAL_CTORS,
+ DCT_GLOBAL_DTORS
+ }
+ type;
+ struct d_info di;
+ struct demangle_component *dc;
+ int status;
+
+ if (mangled[0] == '_' && mangled[1] == 'Z')
+ type = DCT_MANGLED;
+ else if (strncmp (mangled, "_GLOBAL_", 8) == 0
+ && (mangled[8] == '.' || mangled[8] == '_' || mangled[8] == '$')
+ && (mangled[9] == 'D' || mangled[9] == 'I')
+ && mangled[10] == '_')
+ type = mangled[9] == 'I' ? DCT_GLOBAL_CTORS : DCT_GLOBAL_DTORS;
+ else
+ {
+ if ((options & DMGL_TYPES) == 0)
+ return 0;
+ type = DCT_TYPE;
+ }
+
+ cplus_demangle_init_info (mangled, options, strlen (mangled), &di);
+
+ {
+#ifdef CP_DYNAMIC_ARRAYS
+ __extension__ struct demangle_component comps[di.num_comps];
+ __extension__ struct demangle_component *subs[di.num_subs];
+
+ di.comps = comps;
+ di.subs = subs;
+#else
+ di.comps = alloca (di.num_comps * sizeof (*di.comps));
+ di.subs = alloca (di.num_subs * sizeof (*di.subs));
+#endif
+
+ switch (type)
+ {
+ case DCT_TYPE:
+ dc = cplus_demangle_type (&di);
+ break;
+ case DCT_MANGLED:
+ dc = cplus_demangle_mangled_name (&di, 1);
+ break;
+ case DCT_GLOBAL_CTORS:
+ case DCT_GLOBAL_DTORS:
+ d_advance (&di, 11);
+ dc = d_make_comp (&di,
+ (type == DCT_GLOBAL_CTORS
+ ? DEMANGLE_COMPONENT_GLOBAL_CONSTRUCTORS
+ : DEMANGLE_COMPONENT_GLOBAL_DESTRUCTORS),
+ d_make_demangle_mangled_name (&di, d_str (&di)),
+ NULL);
+ d_advance (&di, strlen (d_str (&di)));
+ break;
+ default:
+ abort (); /* We have listed all the cases. */
+ }
+
+ /* If DMGL_PARAMS is set, then if we didn't consume the entire
+ mangled string, then we didn't successfully demangle it. If
+ DMGL_PARAMS is not set, we didn't look at the trailing
+ parameters. */
+ if (((options & DMGL_PARAMS) != 0) && d_peek_char (&di) != '\0')
+ dc = NULL;
+
+#ifdef CP_DEMANGLE_DEBUG
+ d_dump (dc, 0);
+#endif
+
+ status = (dc != NULL)
+ ? cplus_demangle_print_callback (options, dc, callback, opaque)
+ : 0;
+ }
+
+ return status;
+}
+
+/* Entry point for the demangler. If MANGLED is a g++ v3 ABI mangled
+ name, return a buffer allocated with malloc holding the demangled
+ name. OPTIONS is the usual libiberty demangler options. On
+ success, this sets *PALC to the allocated size of the returned
+ buffer. On failure, this sets *PALC to 0 for a bad name, or 1 for
+ a memory allocation failure, and returns NULL. */
+
+static char *
+d_demangle (const char *mangled, int options, size_t *palc)
+{
+ struct d_growable_string dgs;
+ int status;
+
+ d_growable_string_init (&dgs, 0);
+
+ status = d_demangle_callback (mangled, options,
+ d_growable_string_callback_adapter, &dgs);
+ if (status == 0)
+ {
+ free (dgs.buf);
+ *palc = 0;
+ return NULL;
+ }
+
+ *palc = dgs.allocation_failure ? 1 : dgs.alc;
+ return dgs.buf;
+}
+
+#if defined(IN_LIBGCC2) || defined(IN_GLIBCPP_V3)
+
+extern char *__cxa_demangle (const char *, char *, size_t *, int *);
+
+/* ia64 ABI-mandated entry point in the C++ runtime library for
+ performing demangling. MANGLED_NAME is a NUL-terminated character
+ string containing the name to be demangled.
+
+ OUTPUT_BUFFER is a region of memory, allocated with malloc, of
+ *LENGTH bytes, into which the demangled name is stored. If
+ OUTPUT_BUFFER is not long enough, it is expanded using realloc.
+ OUTPUT_BUFFER may instead be NULL; in that case, the demangled name
+ is placed in a region of memory allocated with malloc.
+
+ If LENGTH is non-NULL, the length of the buffer containing the
+ demangled name, is placed in *LENGTH.
+
+ The return value is a pointer to the start of the NUL-terminated
+ demangled name, or NULL if the demangling fails. The caller is
+ responsible for deallocating this memory using free.
+
+ *STATUS is set to one of the following values:
+ 0: The demangling operation succeeded.
+ -1: A memory allocation failure occurred.
+ -2: MANGLED_NAME is not a valid name under the C++ ABI mangling rules.
+ -3: One of the arguments is invalid.
+
+ The demangling is performed using the C++ ABI mangling rules, with
+ GNU extensions. */
+
+char *
+__cxa_demangle (const char *mangled_name, char *output_buffer,
+ size_t *length, int *status)
+{
+ char *demangled;
+ size_t alc;
+
+ if (mangled_name == NULL)
+ {
+ if (status != NULL)
+ *status = -3;
+ return NULL;
+ }
+
+ if (output_buffer != NULL && length == NULL)
+ {
+ if (status != NULL)
+ *status = -3;
+ return NULL;
+ }
+
+ demangled = d_demangle (mangled_name, DMGL_PARAMS | DMGL_TYPES, &alc);
+
+ if (demangled == NULL)
+ {
+ if (status != NULL)
+ {
+ if (alc == 1)
+ *status = -1;
+ else
+ *status = -2;
+ }
+ return NULL;
+ }
+
+ if (output_buffer == NULL)
+ {
+ if (length != NULL)
+ *length = alc;
+ }
+ else
+ {
+ if (strlen (demangled) < *length)
+ {
+ strcpy (output_buffer, demangled);
+ free (demangled);
+ demangled = output_buffer;
+ }
+ else
+ {
+ free (output_buffer);
+ *length = alc;
+ }
+ }
+
+ if (status != NULL)
+ *status = 0;
+
+ return demangled;
+}
+
+extern int __gcclibcxx_demangle_callback (const char *,
+ void (*)
+ (const char *, size_t, void *),
+ void *);
+
+/* Alternative, allocationless entry point in the C++ runtime library
+ for performing demangling. MANGLED_NAME is a NUL-terminated character
+ string containing the name to be demangled.
+
+ CALLBACK is a callback function, called with demangled string
+ segments as demangling progresses; it is called at least once,
+ but may be called more than once. OPAQUE is a generalized pointer
+ used as a callback argument.
+
+ The return code is one of the following values, equivalent to
+ the STATUS values of __cxa_demangle() (excluding -1, since this
+ function performs no memory allocations):
+ 0: The demangling operation succeeded.
+ -2: MANGLED_NAME is not a valid name under the C++ ABI mangling rules.
+ -3: One of the arguments is invalid.
+
+ The demangling is performed using the C++ ABI mangling rules, with
+ GNU extensions. */
+
+int
+__gcclibcxx_demangle_callback (const char *mangled_name,
+ void (*callback) (const char *, size_t, void *),
+ void *opaque)
+{
+ int status;
+
+ if (mangled_name == NULL || callback == NULL)
+ return -3;
+
+ status = d_demangle_callback (mangled_name, DMGL_PARAMS | DMGL_TYPES,
+ callback, opaque);
+ if (status == 0)
+ return -2;
+
+ return 0;
+}
+
+#else /* ! (IN_LIBGCC2 || IN_GLIBCPP_V3) */
+
+/* Entry point for libiberty demangler. If MANGLED is a g++ v3 ABI
+ mangled name, return a buffer allocated with malloc holding the
+ demangled name. Otherwise, return NULL. */
+
+char *
+cplus_demangle_v3 (const char *mangled, int options)
+{
+ size_t alc;
+
+ return d_demangle (mangled, options, &alc);
+}
+
+int
+cplus_demangle_v3_callback (const char *mangled, int options,
+ demangle_callbackref callback, void *opaque)
+{
+ return d_demangle_callback (mangled, options, callback, opaque);
+}
+
+/* Demangle a Java symbol. Java uses a subset of the V3 ABI C++ mangling
+ conventions, but the output formatting is a little different.
+ This instructs the C++ demangler not to emit pointer characters ("*"), to
+ use Java's namespace separator symbol ("." instead of "::"), and to output
+ JArray<TYPE> as TYPE[]. */
+
+char *
+java_demangle_v3 (const char *mangled)
+{
+ size_t alc;
+
+ return d_demangle (mangled, DMGL_JAVA | DMGL_PARAMS | DMGL_RET_POSTFIX, &alc);
+}
+
+int
+java_demangle_v3_callback (const char *mangled,
+ demangle_callbackref callback, void *opaque)
+{
+ return d_demangle_callback (mangled,
+ DMGL_JAVA | DMGL_PARAMS | DMGL_RET_POSTFIX,
+ callback, opaque);
+}
+
+#endif /* IN_LIBGCC2 || IN_GLIBCPP_V3 */
+
+#ifndef IN_GLIBCPP_V3
+
+/* Demangle a string in order to find out whether it is a constructor
+ or destructor. Return non-zero on success. Set *CTOR_KIND and
+ *DTOR_KIND appropriately. */
+
+static int
+is_ctor_or_dtor (const char *mangled,
+ enum gnu_v3_ctor_kinds *ctor_kind,
+ enum gnu_v3_dtor_kinds *dtor_kind)
+{
+ struct d_info di;
+ struct demangle_component *dc;
+ int ret;
+
+ *ctor_kind = (enum gnu_v3_ctor_kinds) 0;
+ *dtor_kind = (enum gnu_v3_dtor_kinds) 0;
+
+ cplus_demangle_init_info (mangled, DMGL_GNU_V3, strlen (mangled), &di);
+
+ {
+#ifdef CP_DYNAMIC_ARRAYS
+ __extension__ struct demangle_component comps[di.num_comps];
+ __extension__ struct demangle_component *subs[di.num_subs];
+
+ di.comps = comps;
+ di.subs = subs;
+#else
+ di.comps = alloca (di.num_comps * sizeof (*di.comps));
+ di.subs = alloca (di.num_subs * sizeof (*di.subs));
+#endif
+
+ dc = cplus_demangle_mangled_name (&di, 1);
+
+ /* Note that because we did not pass DMGL_PARAMS, we don't expect
+ to demangle the entire string. */
+
+ ret = 0;
+ while (dc != NULL)
+ {
+ switch (dc->type)
+ {
+ /* These cannot appear on a constructor or destructor. */
+ case DEMANGLE_COMPONENT_RESTRICT_THIS:
+ case DEMANGLE_COMPONENT_VOLATILE_THIS:
+ case DEMANGLE_COMPONENT_CONST_THIS:
+ case DEMANGLE_COMPONENT_REFERENCE_THIS:
+ case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS:
+ default:
+ dc = NULL;
+ break;
+ case DEMANGLE_COMPONENT_TYPED_NAME:
+ case DEMANGLE_COMPONENT_TEMPLATE:
+ dc = d_left (dc);
+ break;
+ case DEMANGLE_COMPONENT_QUAL_NAME:
+ case DEMANGLE_COMPONENT_LOCAL_NAME:
+ dc = d_right (dc);
+ break;
+ case DEMANGLE_COMPONENT_CTOR:
+ *ctor_kind = dc->u.s_ctor.kind;
+ ret = 1;
+ dc = NULL;
+ break;
+ case DEMANGLE_COMPONENT_DTOR:
+ *dtor_kind = dc->u.s_dtor.kind;
+ ret = 1;
+ dc = NULL;
+ break;
+ }
+ }
+ }
+
+ return ret;
+}
+
+/* Return whether NAME is the mangled form of a g++ V3 ABI constructor
+ name. A non-zero return indicates the type of constructor. */
+
+enum gnu_v3_ctor_kinds
+is_gnu_v3_mangled_ctor (const char *name)
+{
+ enum gnu_v3_ctor_kinds ctor_kind;
+ enum gnu_v3_dtor_kinds dtor_kind;
+
+ if (! is_ctor_or_dtor (name, &ctor_kind, &dtor_kind))
+ return (enum gnu_v3_ctor_kinds) 0;
+ return ctor_kind;
+}
+
+
+/* Return whether NAME is the mangled form of a g++ V3 ABI destructor
+ name. A non-zero return indicates the type of destructor. */
+
+enum gnu_v3_dtor_kinds
+is_gnu_v3_mangled_dtor (const char *name)
+{
+ enum gnu_v3_ctor_kinds ctor_kind;
+ enum gnu_v3_dtor_kinds dtor_kind;
+
+ if (! is_ctor_or_dtor (name, &ctor_kind, &dtor_kind))
+ return (enum gnu_v3_dtor_kinds) 0;
+ return dtor_kind;
+}
+
+#endif /* IN_GLIBCPP_V3 */
+
+#ifdef STANDALONE_DEMANGLER
+
+#include "getopt.h"
+#include "dyn-string.h"
+
+static void print_usage (FILE* fp, int exit_value);
+
+#define IS_ALPHA(CHAR) \
+ (((CHAR) >= 'a' && (CHAR) <= 'z') \
+ || ((CHAR) >= 'A' && (CHAR) <= 'Z'))
+
+/* Non-zero if CHAR is a character than can occur in a mangled name. */
+#define is_mangled_char(CHAR) \
+ (IS_ALPHA (CHAR) || IS_DIGIT (CHAR) \
+ || (CHAR) == '_' || (CHAR) == '.' || (CHAR) == '$')
+
+/* The name of this program, as invoked. */
+const char* program_name;
+
+/* Prints usage summary to FP and then exits with EXIT_VALUE. */
+
+static void
+print_usage (FILE* fp, int exit_value)
+{
+ fprintf (fp, "Usage: %s [options] [names ...]\n", program_name);
+ fprintf (fp, "Options:\n");
+ fprintf (fp, " -h,--help Display this message.\n");
+ fprintf (fp, " -p,--no-params Don't display function parameters\n");
+ fprintf (fp, " -v,--verbose Produce verbose demanglings.\n");
+ fprintf (fp, "If names are provided, they are demangled. Otherwise filters standard input.\n");
+
+ exit (exit_value);
+}
+
+/* Option specification for getopt_long. */
+static const struct option long_options[] =
+{
+ { "help", no_argument, NULL, 'h' },
+ { "no-params", no_argument, NULL, 'p' },
+ { "verbose", no_argument, NULL, 'v' },
+ { NULL, no_argument, NULL, 0 },
+};
+
+/* Main entry for a demangling filter executable. It will demangle
+ its command line arguments, if any. If none are provided, it will
+ filter stdin to stdout, replacing any recognized mangled C++ names
+ with their demangled equivalents. */
+
+int
+main (int argc, char *argv[])
+{
+ int i;
+ int opt_char;
+ int options = DMGL_PARAMS | DMGL_ANSI | DMGL_TYPES;
+
+ /* Use the program name of this program, as invoked. */
+ program_name = argv[0];
+
+ /* Parse options. */
+ do
+ {
+ opt_char = getopt_long (argc, argv, "hpv", long_options, NULL);
+ switch (opt_char)
+ {
+ case '?': /* Unrecognized option. */
+ print_usage (stderr, 1);
+ break;
+
+ case 'h':
+ print_usage (stdout, 0);
+ break;
+
+ case 'p':
+ options &= ~ DMGL_PARAMS;
+ break;
+
+ case 'v':
+ options |= DMGL_VERBOSE;
+ break;
+ }
+ }
+ while (opt_char != -1);
+
+ if (optind == argc)
+ /* No command line arguments were provided. Filter stdin. */
+ {
+ dyn_string_t mangled = dyn_string_new (3);
+ char *s;
+
+ /* Read all of input. */
+ while (!feof (stdin))
+ {
+ char c;
+
+ /* Pile characters into mangled until we hit one that can't
+ occur in a mangled name. */
+ c = getchar ();
+ while (!feof (stdin) && is_mangled_char (c))
+ {
+ dyn_string_append_char (mangled, c);
+ if (feof (stdin))
+ break;
+ c = getchar ();
+ }
+
+ if (dyn_string_length (mangled) > 0)
+ {
+#ifdef IN_GLIBCPP_V3
+ s = __cxa_demangle (dyn_string_buf (mangled), NULL, NULL, NULL);
+#else
+ s = cplus_demangle_v3 (dyn_string_buf (mangled), options);
+#endif
+
+ if (s != NULL)
+ {
+ fputs (s, stdout);
+ free (s);
+ }
+ else
+ {
+ /* It might not have been a mangled name. Print the
+ original text. */
+ fputs (dyn_string_buf (mangled), stdout);
+ }
+
+ dyn_string_clear (mangled);
+ }
+
+ /* If we haven't hit EOF yet, we've read one character that
+ can't occur in a mangled name, so print it out. */
+ if (!feof (stdin))
+ putchar (c);
+ }
+
+ dyn_string_delete (mangled);
+ }
+ else
+ /* Demangle command line arguments. */
+ {
+ /* Loop over command line arguments. */
+ for (i = optind; i < argc; ++i)
+ {
+ char *s;
+#ifdef IN_GLIBCPP_V3
+ int status;
+#endif
+
+ /* Attempt to demangle. */
+#ifdef IN_GLIBCPP_V3
+ s = __cxa_demangle (argv[i], NULL, NULL, &status);
+#else
+ s = cplus_demangle_v3 (argv[i], options);
+#endif
+
+ /* If it worked, print the demangled name. */
+ if (s != NULL)
+ {
+ printf ("%s\n", s);
+ free (s);
+ }
+ else
+ {
+#ifdef IN_GLIBCPP_V3
+ fprintf (stderr, "Failed: %s (status %d)\n", argv[i], status);
+#else
+ fprintf (stderr, "Failed: %s\n", argv[i]);
+#endif
+ }
+ }
+ }
+
+ return 0;
+}
+
+#endif /* STANDALONE_DEMANGLER */
+
+#endif /* !defined(LW_CFG_CPU_ARCH_C6X) && (LW_CFG_MODULELOADER_EN > 0) */
diff --git a/SylixOS/bintools/demangle/cp-demangle.h b/SylixOS/bintools/demangle/cp-demangle.h
new file mode 100644
index 0000000..6fce025
--- /dev/null
+++ b/SylixOS/bintools/demangle/cp-demangle.h
@@ -0,0 +1,174 @@
+/* Internal demangler interface for g++ V3 ABI.
+ Copyright (C) 2003, 2004, 2005, 2006, 2007, 2010
+ Free Software Foundation, Inc.
+ Written by Ian Lance Taylor <ian@wasabisystems.com>.
+
+ This file is part of the libiberty library, which is part of GCC.
+
+ This file is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ In addition to the permissions in the GNU General Public License, the
+ Free Software Foundation gives you unlimited permission to link the
+ compiled version of this file into combinations with other programs,
+ and to distribute those combinations without any restriction coming
+ from the use of this file. (The General Public License restrictions
+ do apply in other respects; for example, they cover modification of
+ the file, and distribution when not linked into a combined
+ executable.)
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+/* This file provides some definitions shared by cp-demangle.c and
+ cp-demint.c. It should not be included by any other files. */
+
+/* Information we keep for operators. */
+
+struct demangle_operator_info
+{
+ /* Mangled name. */
+ const char *code;
+ /* Real name. */
+ const char *name;
+ /* Length of real name. */
+ int len;
+ /* Number of arguments. */
+ int args;
+};
+
+/* How to print the value of a builtin type. */
+
+enum d_builtin_type_print
+{
+ /* Print as (type)val. */
+ D_PRINT_DEFAULT,
+ /* Print as integer. */
+ D_PRINT_INT,
+ /* Print as unsigned integer, with trailing "u". */
+ D_PRINT_UNSIGNED,
+ /* Print as long, with trailing "l". */
+ D_PRINT_LONG,
+ /* Print as unsigned long, with trailing "ul". */
+ D_PRINT_UNSIGNED_LONG,
+ /* Print as long long, with trailing "ll". */
+ D_PRINT_LONG_LONG,
+ /* Print as unsigned long long, with trailing "ull". */
+ D_PRINT_UNSIGNED_LONG_LONG,
+ /* Print as bool. */
+ D_PRINT_BOOL,
+ /* Print as float--put value in square brackets. */
+ D_PRINT_FLOAT,
+ /* Print in usual way, but here to detect void. */
+ D_PRINT_VOID
+};
+
+/* Information we keep for a builtin type. */
+
+struct demangle_builtin_type_info
+{
+ /* Type name. */
+ const char *name;
+ /* Length of type name. */
+ int len;
+ /* Type name when using Java. */
+ const char *java_name;
+ /* Length of java name. */
+ int java_len;
+ /* How to print a value of this type. */
+ enum d_builtin_type_print print;
+};
+
+/* The information structure we pass around. */
+
+struct d_info
+{
+ /* The string we are demangling. */
+ const char *s;
+ /* The end of the string we are demangling. */
+ const char *send;
+ /* The options passed to the demangler. */
+ int options;
+ /* The next character in the string to consider. */
+ const char *n;
+ /* The array of components. */
+ struct demangle_component *comps;
+ /* The index of the next available component. */
+ int next_comp;
+ /* The number of available component structures. */
+ int num_comps;
+ /* The array of substitutions. */
+ struct demangle_component **subs;
+ /* The index of the next substitution. */
+ int next_sub;
+ /* The number of available entries in the subs array. */
+ int num_subs;
+ /* The number of substitutions which we actually made from the subs
+ array, plus the number of template parameter references we
+ saw. */
+ int did_subs;
+ /* The last name we saw, for constructors and destructors. */
+ struct demangle_component *last_name;
+ /* A running total of the length of large expansions from the
+ mangled name to the demangled name, such as standard
+ substitutions and builtin types. */
+ int expansion;
+ /* Non-zero if we are parsing an expression. */
+ int is_expression;
+ /* Non-zero if we are parsing the type operand of a conversion
+ operator, but not when in an expression. */
+ int is_conversion;
+};
+
+/* To avoid running past the ending '\0', don't:
+ - call d_peek_next_char if d_peek_char returned '\0'
+ - call d_advance with an 'i' that is too large
+ - call d_check_char(di, '\0')
+ Everything else is safe. */
+#define d_peek_char(di) (*((di)->n))
+#define d_peek_next_char(di) ((di)->n[1])
+#define d_advance(di, i) ((di)->n += (i))
+#define d_check_char(di, c) (d_peek_char(di) == c ? ((di)->n++, 1) : 0)
+#define d_next_char(di) (d_peek_char(di) == '\0' ? '\0' : *((di)->n++))
+#define d_str(di) ((di)->n)
+
+/* Functions and arrays in cp-demangle.c which are referenced by
+ functions in cp-demint.c. */
+#ifdef IN_GLIBCPP_V3
+#define CP_STATIC_IF_GLIBCPP_V3 static
+#else
+#define CP_STATIC_IF_GLIBCPP_V3 extern
+#endif
+
+#ifndef IN_GLIBCPP_V3
+extern const struct demangle_operator_info cplus_demangle_operators[];
+#endif
+
+#define D_BUILTIN_TYPE_COUNT (33)
+
+CP_STATIC_IF_GLIBCPP_V3
+const struct demangle_builtin_type_info
+cplus_demangle_builtin_types[D_BUILTIN_TYPE_COUNT];
+
+CP_STATIC_IF_GLIBCPP_V3
+struct demangle_component *
+cplus_demangle_mangled_name (struct d_info *, int);
+
+CP_STATIC_IF_GLIBCPP_V3
+struct demangle_component *
+cplus_demangle_type (struct d_info *);
+
+extern void
+cplus_demangle_init_info (const char *, int, size_t, struct d_info *);
+
+/* cp-demangle.c needs to define this a little differently */
+#undef CP_STATIC_IF_GLIBCPP_V3
diff --git a/SylixOS/bintools/demangle/cp-demint.c b/SylixOS/bintools/demangle/cp-demint.c
new file mode 100644
index 0000000..b5c9e1c
--- /dev/null
+++ b/SylixOS/bintools/demangle/cp-demint.c
@@ -0,0 +1,264 @@
+/* Demangler component interface functions.
+ Copyright (C) 2004 Free Software Foundation, Inc.
+ Written by Ian Lance Taylor <ian@wasabisystems.com>.
+
+ This file is part of the libiberty library, which is part of GCC.
+
+ This file is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ In addition to the permissions in the GNU General Public License, the
+ Free Software Foundation gives you unlimited permission to link the
+ compiled version of this file into combinations with other programs,
+ and to distribute those combinations without any restriction coming
+ from the use of this file. (The General Public License restrictions
+ do apply in other respects; for example, they cover modification of
+ the file, and distribution when not linked into a combined
+ executable.)
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+/* This file implements a few interface functions which are provided
+ for use with struct demangle_component trees. These functions are
+ declared in demangle.h. These functions are closely tied to the
+ demangler code in cp-demangle.c, and other interface functions can
+ be found in that file. We put these functions in a separate file
+ because they are not needed by the demangler, and so we avoid
+ having them pulled in by programs which only need the
+ demangler. */
+
+#include "SylixOS.h"
+
+/*
+ * configure options for SylixOS
+ */
+#define HAVE_STDLIB_H
+#define HAVE_STRING_H
+#define HAVE_ALLOCA_H
+#define IN_LIBGCC2
+
+/*
+ * undefine symbols on SylixOS
+ *
+ * $ nm -u cp-demint.o
+ * U cplus_demangle_builtin_types
+ * U cplus_demangle_init_info
+ * U cplus_demangle_mangled_name
+ * U cplus_demangle_operators
+ * U cplus_demangle_type
+ * U free
+ * U malloc
+ * U strcmp
+ * U strlen
+ */
+
+/*
+ * c6x librts.a has __cxa_demangle() function
+ */
+#if !defined(LW_CFG_CPU_ARCH_C6X) && (LW_CFG_MODULELOADER_EN > 0)
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#include "ansidecl.h"
+#include "libiberty.h"
+#include "demangle.h"
+#include "cp-demangle.h"
+
+/* Fill in most component types. */
+
+int
+cplus_demangle_fill_component (struct demangle_component *p,
+ enum demangle_component_type type,
+ struct demangle_component *left,
+ struct demangle_component *right)
+{
+ if (p == NULL)
+ return 0;
+ switch (type)
+ {
+ case DEMANGLE_COMPONENT_QUAL_NAME:
+ case DEMANGLE_COMPONENT_LOCAL_NAME:
+ case DEMANGLE_COMPONENT_TYPED_NAME:
+ case DEMANGLE_COMPONENT_TEMPLATE:
+ case DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE:
+ case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL:
+ case DEMANGLE_COMPONENT_FUNCTION_TYPE:
+ case DEMANGLE_COMPONENT_ARRAY_TYPE:
+ case DEMANGLE_COMPONENT_PTRMEM_TYPE:
+ case DEMANGLE_COMPONENT_ARGLIST:
+ case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST:
+ case DEMANGLE_COMPONENT_UNARY:
+ case DEMANGLE_COMPONENT_BINARY:
+ case DEMANGLE_COMPONENT_BINARY_ARGS:
+ case DEMANGLE_COMPONENT_TRINARY:
+ case DEMANGLE_COMPONENT_TRINARY_ARG1:
+ case DEMANGLE_COMPONENT_TRINARY_ARG2:
+ case DEMANGLE_COMPONENT_LITERAL:
+ case DEMANGLE_COMPONENT_LITERAL_NEG:
+ break;
+
+ /* These component types only have one subtree. */
+ case DEMANGLE_COMPONENT_VTABLE:
+ case DEMANGLE_COMPONENT_VTT:
+ case DEMANGLE_COMPONENT_TYPEINFO:
+ case DEMANGLE_COMPONENT_TYPEINFO_NAME:
+ case DEMANGLE_COMPONENT_TYPEINFO_FN:
+ case DEMANGLE_COMPONENT_THUNK:
+ case DEMANGLE_COMPONENT_VIRTUAL_THUNK:
+ case DEMANGLE_COMPONENT_COVARIANT_THUNK:
+ case DEMANGLE_COMPONENT_JAVA_CLASS:
+ case DEMANGLE_COMPONENT_GUARD:
+ case DEMANGLE_COMPONENT_REFTEMP:
+ case DEMANGLE_COMPONENT_RESTRICT:
+ case DEMANGLE_COMPONENT_VOLATILE:
+ case DEMANGLE_COMPONENT_CONST:
+ case DEMANGLE_COMPONENT_RESTRICT_THIS:
+ case DEMANGLE_COMPONENT_VOLATILE_THIS:
+ case DEMANGLE_COMPONENT_CONST_THIS:
+ case DEMANGLE_COMPONENT_POINTER:
+ case DEMANGLE_COMPONENT_REFERENCE:
+ case DEMANGLE_COMPONENT_COMPLEX:
+ case DEMANGLE_COMPONENT_IMAGINARY:
+ case DEMANGLE_COMPONENT_VENDOR_TYPE:
+ case DEMANGLE_COMPONENT_CAST:
+ if (right != NULL)
+ return 0;
+ break;
+
+ default:
+ /* Other types do not use subtrees. */
+ return 0;
+ }
+
+ p->type = type;
+ p->u.s_binary.left = left;
+ p->u.s_binary.right = right;
+
+ return 1;
+}
+
+/* Fill in a DEMANGLE_COMPONENT_BUILTIN_TYPE. */
+
+int
+cplus_demangle_fill_builtin_type (struct demangle_component *p,
+ const char *type_name)
+{
+ int len;
+ unsigned int i;
+
+ if (p == NULL || type_name == NULL)
+ return 0;
+ len = strlen (type_name);
+ for (i = 0; i < D_BUILTIN_TYPE_COUNT; ++i)
+ {
+ if (len == cplus_demangle_builtin_types[i].len
+ && strcmp (type_name, cplus_demangle_builtin_types[i].name) == 0)
+ {
+ p->type = DEMANGLE_COMPONENT_BUILTIN_TYPE;
+ p->u.s_builtin.type = &cplus_demangle_builtin_types[i];
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* Fill in a DEMANGLE_COMPONENT_OPERATOR. */
+
+int
+cplus_demangle_fill_operator (struct demangle_component *p,
+ const char *opname, int args)
+{
+ int len;
+ unsigned int i;
+
+ if (p == NULL || opname == NULL)
+ return 0;
+ len = strlen (opname);
+ for (i = 0; cplus_demangle_operators[i].name != NULL; ++i)
+ {
+ if (len == cplus_demangle_operators[i].len
+ && args == cplus_demangle_operators[i].args
+ && strcmp (opname, cplus_demangle_operators[i].name) == 0)
+ {
+ p->type = DEMANGLE_COMPONENT_OPERATOR;
+ p->u.s_operator.op = &cplus_demangle_operators[i];
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* Translate a mangled name into components. */
+
+struct demangle_component *
+cplus_demangle_v3_components (const char *mangled, int options, void **mem)
+{
+ size_t len;
+ int type;
+ struct d_info di;
+ struct demangle_component *dc;
+
+ len = strlen (mangled);
+
+ if (mangled[0] == '_' && mangled[1] == 'Z')
+ type = 0;
+ else
+ {
+ if ((options & DMGL_TYPES) == 0)
+ return NULL;
+ type = 1;
+ }
+
+ cplus_demangle_init_info (mangled, options, len, &di);
+
+ di.comps = ((struct demangle_component *)
+ malloc (di.num_comps * sizeof (struct demangle_component)));
+ di.subs = ((struct demangle_component **)
+ malloc (di.num_subs * sizeof (struct demangle_component *)));
+ if (di.comps == NULL || di.subs == NULL)
+ {
+ free (di.comps);
+ free (di.subs);
+ return NULL;
+ }
+
+ if (! type)
+ dc = cplus_demangle_mangled_name (&di, 1);
+ else
+ dc = cplus_demangle_type (&di);
+
+ /* If DMGL_PARAMS is set, then if we didn't consume the entire
+ mangled string, then we didn't successfully demangle it. */
+ if ((options & DMGL_PARAMS) != 0 && d_peek_char (&di) != '\0')
+ dc = NULL;
+
+ free (di.subs);
+
+ if (dc != NULL)
+ *mem = di.comps;
+ else
+ free (di.comps);
+
+ return dc;
+}
+
+#endif /* !defined(LW_CFG_CPU_ARCH_C6X) && (LW_CFG_MODULELOADER_EN > 0) */
diff --git a/SylixOS/bintools/demangle/demangle.c b/SylixOS/bintools/demangle/demangle.c
new file mode 100644
index 0000000..0b957dc
--- /dev/null
+++ b/SylixOS/bintools/demangle/demangle.c
@@ -0,0 +1,35 @@
+/*
+ * SylixOS(TM) LW : long wing
+ * Copyright All Rights Reserved
+ *
+ * /bin/demangle /usr/bin/demangle
+ *
+ * Author: Jiao.JinXing <jiaojinxing1987@gmail.com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+extern char *__cxa_demangle(const char *mangled, char *buf, size_t *len, int *status);
+
+int main (int argc, char **argv)
+{
+ char *demangle_name;
+ int status;
+
+ if (argc < 2) {
+ printf("Usage: %s mangle_name\n", argv[0]);
+ return (-1);
+ }
+
+ demangle_name = __cxa_demangle(argv[1], NULL, NULL, &status);
+ if (demangle_name && (status == 0)) {
+ printf("%s\n", demangle_name);
+ free(demangle_name);
+ return (0);
+
+ } else {
+ printf("failed to demangle %s\n", argv[1]);
+ return (-1);
+ }
+}
diff --git a/SylixOS/bintools/demangle/demangle.h b/SylixOS/bintools/demangle/demangle.h
new file mode 100644
index 0000000..bbad71b
--- /dev/null
+++ b/SylixOS/bintools/demangle/demangle.h
@@ -0,0 +1,679 @@
+/* Defs for interface to demanglers.
+ Copyright 1992, 1993, 1994, 1995, 1996, 1997, 1998, 2000, 2001, 2002,
+ 2003, 2004, 2005, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License
+ as published by the Free Software Foundation; either version 2, or
+ (at your option) any later version.
+
+ In addition to the permissions in the GNU Library General Public
+ License, the Free Software Foundation gives you unlimited
+ permission to link the compiled version of this file into
+ combinations with other programs, and to distribute those
+ combinations without any restriction coming from the use of this
+ file. (The Library Public License restrictions do apply in other
+ respects; for example, they cover modification of the file, and
+ distribution when not linked into a combined executable.)
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+
+
+#if !defined (DEMANGLE_H)
+#define DEMANGLE_H
+
+#include "libiberty.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/* Options passed to cplus_demangle (in 2nd parameter). */
+
+#define DMGL_NO_OPTS 0 /* For readability... */
+#define DMGL_PARAMS (1 << 0) /* Include function args */
+#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */
+#define DMGL_JAVA (1 << 2) /* Demangle as Java rather than C++. */
+#define DMGL_VERBOSE (1 << 3) /* Include implementation details. */
+#define DMGL_TYPES (1 << 4) /* Also try to demangle type encodings. */
+#define DMGL_RET_POSTFIX (1 << 5) /* Print function return types (when
+ present) after function signature.
+ It applies only to the toplevel
+ function type. */
+#define DMGL_RET_DROP (1 << 6) /* Suppress printing function return
+ types, even if present. It applies
+ only to the toplevel function type.
+ */
+
+#define DMGL_AUTO (1 << 8)
+#define DMGL_GNU (1 << 9)
+#define DMGL_LUCID (1 << 10)
+#define DMGL_ARM (1 << 11)
+#define DMGL_HP (1 << 12) /* For the HP aCC compiler;
+ same as ARM except for
+ template arguments, etc. */
+#define DMGL_EDG (1 << 13)
+#define DMGL_GNU_V3 (1 << 14)
+#define DMGL_GNAT (1 << 15)
+
+/* If none of these are set, use 'current_demangling_style' as the default. */
+#define DMGL_STYLE_MASK (DMGL_AUTO|DMGL_GNU|DMGL_LUCID|DMGL_ARM|DMGL_HP|DMGL_EDG|DMGL_GNU_V3|DMGL_JAVA|DMGL_GNAT)
+
+/* Enumeration of possible demangling styles.
+
+ Lucid and ARM styles are still kept logically distinct, even though
+ they now both behave identically. The resulting style is actual the
+ union of both. I.E. either style recognizes both "__pt__" and "__rf__"
+ for operator "->", even though the first is lucid style and the second
+ is ARM style. (FIXME?) */
+
+extern enum demangling_styles
+{
+ no_demangling = -1,
+ unknown_demangling = 0,
+ auto_demangling = DMGL_AUTO,
+ gnu_demangling = DMGL_GNU,
+ lucid_demangling = DMGL_LUCID,
+ arm_demangling = DMGL_ARM,
+ hp_demangling = DMGL_HP,
+ edg_demangling = DMGL_EDG,
+ gnu_v3_demangling = DMGL_GNU_V3,
+ java_demangling = DMGL_JAVA,
+ gnat_demangling = DMGL_GNAT
+} current_demangling_style;
+
+/* Define string names for the various demangling styles. */
+
+#define NO_DEMANGLING_STYLE_STRING "none"
+#define AUTO_DEMANGLING_STYLE_STRING "auto"
+#define GNU_DEMANGLING_STYLE_STRING "gnu"
+#define LUCID_DEMANGLING_STYLE_STRING "lucid"
+#define ARM_DEMANGLING_STYLE_STRING "arm"
+#define HP_DEMANGLING_STYLE_STRING "hp"
+#define EDG_DEMANGLING_STYLE_STRING "edg"
+#define GNU_V3_DEMANGLING_STYLE_STRING "gnu-v3"
+#define JAVA_DEMANGLING_STYLE_STRING "java"
+#define GNAT_DEMANGLING_STYLE_STRING "gnat"
+
+/* Some macros to test what demangling style is active. */
+
+#define CURRENT_DEMANGLING_STYLE current_demangling_style
+#define AUTO_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_AUTO)
+#define GNU_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_GNU)
+#define LUCID_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_LUCID)
+#define ARM_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_ARM)
+#define HP_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_HP)
+#define EDG_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_EDG)
+#define GNU_V3_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_GNU_V3)
+#define JAVA_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_JAVA)
+#define GNAT_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_GNAT)
+
+/* Provide information about the available demangle styles. This code is
+ pulled from gdb into libiberty because it is useful to binutils also. */
+
+extern const struct demangler_engine
+{
+ const char *const demangling_style_name;
+ const enum demangling_styles demangling_style;
+ const char *const demangling_style_doc;
+} libiberty_demanglers[];
+
+extern char *
+cplus_demangle (const char *mangled, int options);
+
+extern int
+cplus_demangle_opname (const char *opname, char *result, int options);
+
+extern const char *
+cplus_mangle_opname (const char *opname, int options);
+
+/* Note: This sets global state. FIXME if you care about multi-threading. */
+
+extern void
+set_cplus_marker_for_demangling (int ch);
+
+extern enum demangling_styles
+cplus_demangle_set_style (enum demangling_styles style);
+
+extern enum demangling_styles
+cplus_demangle_name_to_style (const char *name);
+
+/* Callback typedef for allocation-less demangler interfaces. */
+typedef void (*demangle_callbackref) (const char *, size_t, void *);
+
+/* V3 ABI demangling entry points, defined in cp-demangle.c. Callback
+ variants return non-zero on success, zero on error. char* variants
+ return a string allocated by malloc on success, NULL on error. */
+extern int
+cplus_demangle_v3_callback (const char *mangled, int options,
+ demangle_callbackref callback, void *opaque);
+
+extern char*
+cplus_demangle_v3 (const char *mangled, int options);
+
+extern int
+java_demangle_v3_callback (const char *mangled,
+ demangle_callbackref callback, void *opaque);
+
+extern char*
+java_demangle_v3 (const char *mangled);
+
+char *
+ada_demangle (const char *mangled, int options);
+
+enum gnu_v3_ctor_kinds {
+ gnu_v3_complete_object_ctor = 1,
+ gnu_v3_base_object_ctor,
+ gnu_v3_complete_object_allocating_ctor,
+ /* These are not part of the V3 ABI. Unified constructors are generated
+ as a speed-for-space optimization when the -fdeclone-ctor-dtor option
+ is used, and are always internal symbols. */
+ gnu_v3_unified_ctor,
+ gnu_v3_object_ctor_group
+};
+
+/* Return non-zero iff NAME is the mangled form of a constructor name
+ in the G++ V3 ABI demangling style. Specifically, return an `enum
+ gnu_v3_ctor_kinds' value indicating what kind of constructor
+ it is. */
+extern enum gnu_v3_ctor_kinds
+ is_gnu_v3_mangled_ctor (const char *name);
+
+
+enum gnu_v3_dtor_kinds {
+ gnu_v3_deleting_dtor = 1,
+ gnu_v3_complete_object_dtor,
+ gnu_v3_base_object_dtor,
+ /* These are not part of the V3 ABI. Unified destructors are generated
+ as a speed-for-space optimization when the -fdeclone-ctor-dtor option
+ is used, and are always internal symbols. */
+ gnu_v3_unified_dtor,
+ gnu_v3_object_dtor_group
+};
+
+/* Return non-zero iff NAME is the mangled form of a destructor name
+ in the G++ V3 ABI demangling style. Specifically, return an `enum
+ gnu_v3_dtor_kinds' value, indicating what kind of destructor
+ it is. */
+extern enum gnu_v3_dtor_kinds
+ is_gnu_v3_mangled_dtor (const char *name);
+
+/* The V3 demangler works in two passes. The first pass builds a tree
+ representation of the mangled name, and the second pass turns the
+ tree representation into a demangled string. Here we define an
+ interface to permit a caller to build their own tree
+ representation, which they can pass to the demangler to get a
+ demangled string. This can be used to canonicalize user input into
+ something which the demangler might output. It could also be used
+ by other demanglers in the future. */
+
+/* These are the component types which may be found in the tree. Many
+ component types have one or two subtrees, referred to as left and
+ right (a component type with only one subtree puts it in the left
+ subtree). */
+
+enum demangle_component_type
+{
+ /* A name, with a length and a pointer to a string. */
+ DEMANGLE_COMPONENT_NAME,
+ /* A qualified name. The left subtree is a class or namespace or
+ some such thing, and the right subtree is a name qualified by
+ that class. */
+ DEMANGLE_COMPONENT_QUAL_NAME,
+ /* A local name. The left subtree describes a function, and the
+ right subtree is a name which is local to that function. */
+ DEMANGLE_COMPONENT_LOCAL_NAME,
+ /* A typed name. The left subtree is a name, and the right subtree
+ describes that name as a function. */
+ DEMANGLE_COMPONENT_TYPED_NAME,
+ /* A template. The left subtree is a template name, and the right
+ subtree is a template argument list. */
+ DEMANGLE_COMPONENT_TEMPLATE,
+ /* A template parameter. This holds a number, which is the template
+ parameter index. */
+ DEMANGLE_COMPONENT_TEMPLATE_PARAM,
+ /* A function parameter. This holds a number, which is the index. */
+ DEMANGLE_COMPONENT_FUNCTION_PARAM,
+ /* A constructor. This holds a name and the kind of
+ constructor. */
+ DEMANGLE_COMPONENT_CTOR,
+ /* A destructor. This holds a name and the kind of destructor. */
+ DEMANGLE_COMPONENT_DTOR,
+ /* A vtable. This has one subtree, the type for which this is a
+ vtable. */
+ DEMANGLE_COMPONENT_VTABLE,
+ /* A VTT structure. This has one subtree, the type for which this
+ is a VTT. */
+ DEMANGLE_COMPONENT_VTT,
+ /* A construction vtable. The left subtree is the type for which
+ this is a vtable, and the right subtree is the derived type for
+ which this vtable is built. */
+ DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE,
+ /* A typeinfo structure. This has one subtree, the type for which
+ this is the tpeinfo structure. */
+ DEMANGLE_COMPONENT_TYPEINFO,
+ /* A typeinfo name. This has one subtree, the type for which this
+ is the typeinfo name. */
+ DEMANGLE_COMPONENT_TYPEINFO_NAME,
+ /* A typeinfo function. This has one subtree, the type for which
+ this is the tpyeinfo function. */
+ DEMANGLE_COMPONENT_TYPEINFO_FN,
+ /* A thunk. This has one subtree, the name for which this is a
+ thunk. */
+ DEMANGLE_COMPONENT_THUNK,
+ /* A virtual thunk. This has one subtree, the name for which this
+ is a virtual thunk. */
+ DEMANGLE_COMPONENT_VIRTUAL_THUNK,
+ /* A covariant thunk. This has one subtree, the name for which this
+ is a covariant thunk. */
+ DEMANGLE_COMPONENT_COVARIANT_THUNK,
+ /* A Java class. This has one subtree, the type. */
+ DEMANGLE_COMPONENT_JAVA_CLASS,
+ /* A guard variable. This has one subtree, the name for which this
+ is a guard variable. */
+ DEMANGLE_COMPONENT_GUARD,
+ /* The init and wrapper functions for C++11 thread_local variables. */
+ DEMANGLE_COMPONENT_TLS_INIT,
+ DEMANGLE_COMPONENT_TLS_WRAPPER,
+ /* A reference temporary. This has one subtree, the name for which
+ this is a temporary. */
+ DEMANGLE_COMPONENT_REFTEMP,
+ /* A hidden alias. This has one subtree, the encoding for which it
+ is providing alternative linkage. */
+ DEMANGLE_COMPONENT_HIDDEN_ALIAS,
+ /* A standard substitution. This holds the name of the
+ substitution. */
+ DEMANGLE_COMPONENT_SUB_STD,
+ /* The restrict qualifier. The one subtree is the type which is
+ being qualified. */
+ DEMANGLE_COMPONENT_RESTRICT,
+ /* The volatile qualifier. The one subtree is the type which is
+ being qualified. */
+ DEMANGLE_COMPONENT_VOLATILE,
+ /* The const qualifier. The one subtree is the type which is being
+ qualified. */
+ DEMANGLE_COMPONENT_CONST,
+ /* The restrict qualifier modifying a member function. The one
+ subtree is the type which is being qualified. */
+ DEMANGLE_COMPONENT_RESTRICT_THIS,
+ /* The volatile qualifier modifying a member function. The one
+ subtree is the type which is being qualified. */
+ DEMANGLE_COMPONENT_VOLATILE_THIS,
+ /* The const qualifier modifying a member function. The one subtree
+ is the type which is being qualified. */
+ DEMANGLE_COMPONENT_CONST_THIS,
+ /* C++11 A reference modifying a member function. The one subtree is the
+ type which is being referenced. */
+ DEMANGLE_COMPONENT_REFERENCE_THIS,
+ /* C++11: An rvalue reference modifying a member function. The one
+ subtree is the type which is being referenced. */
+ DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS,
+ /* A vendor qualifier. The left subtree is the type which is being
+ qualified, and the right subtree is the name of the
+ qualifier. */
+ DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL,
+ /* A pointer. The one subtree is the type which is being pointed
+ to. */
+ DEMANGLE_COMPONENT_POINTER,
+ /* A reference. The one subtree is the type which is being
+ referenced. */
+ DEMANGLE_COMPONENT_REFERENCE,
+ /* C++0x: An rvalue reference. The one subtree is the type which is
+ being referenced. */
+ DEMANGLE_COMPONENT_RVALUE_REFERENCE,
+ /* A complex type. The one subtree is the base type. */
+ DEMANGLE_COMPONENT_COMPLEX,
+ /* An imaginary type. The one subtree is the base type. */
+ DEMANGLE_COMPONENT_IMAGINARY,
+ /* A builtin type. This holds the builtin type information. */
+ DEMANGLE_COMPONENT_BUILTIN_TYPE,
+ /* A vendor's builtin type. This holds the name of the type. */
+ DEMANGLE_COMPONENT_VENDOR_TYPE,
+ /* A function type. The left subtree is the return type. The right
+ subtree is a list of ARGLIST nodes. Either or both may be
+ NULL. */
+ DEMANGLE_COMPONENT_FUNCTION_TYPE,
+ /* An array type. The left subtree is the dimension, which may be
+ NULL, or a string (represented as DEMANGLE_COMPONENT_NAME), or an
+ expression. The right subtree is the element type. */
+ DEMANGLE_COMPONENT_ARRAY_TYPE,
+ /* A pointer to member type. The left subtree is the class type,
+ and the right subtree is the member type. CV-qualifiers appear
+ on the latter. */
+ DEMANGLE_COMPONENT_PTRMEM_TYPE,
+ /* A fixed-point type. */
+ DEMANGLE_COMPONENT_FIXED_TYPE,
+ /* A vector type. The left subtree is the number of elements,
+ the right subtree is the element type. */
+ DEMANGLE_COMPONENT_VECTOR_TYPE,
+ /* An argument list. The left subtree is the current argument, and
+ the right subtree is either NULL or another ARGLIST node. */
+ DEMANGLE_COMPONENT_ARGLIST,
+ /* A template argument list. The left subtree is the current
+ template argument, and the right subtree is either NULL or
+ another TEMPLATE_ARGLIST node. */
+ DEMANGLE_COMPONENT_TEMPLATE_ARGLIST,
+ /* An initializer list. The left subtree is either an explicit type or
+ NULL, and the right subtree is a DEMANGLE_COMPONENT_ARGLIST. */
+ DEMANGLE_COMPONENT_INITIALIZER_LIST,
+ /* An operator. This holds information about a standard
+ operator. */
+ DEMANGLE_COMPONENT_OPERATOR,
+ /* An extended operator. This holds the number of arguments, and
+ the name of the extended operator. */
+ DEMANGLE_COMPONENT_EXTENDED_OPERATOR,
+ /* A typecast, represented as a unary operator. The one subtree is
+ the type to which the argument should be cast. */
+ DEMANGLE_COMPONENT_CAST,
+ /* A nullary expression. The left subtree is the operator. */
+ DEMANGLE_COMPONENT_NULLARY,
+ /* A unary expression. The left subtree is the operator, and the
+ right subtree is the single argument. */
+ DEMANGLE_COMPONENT_UNARY,
+ /* A binary expression. The left subtree is the operator, and the
+ right subtree is a BINARY_ARGS. */
+ DEMANGLE_COMPONENT_BINARY,
+ /* Arguments to a binary expression. The left subtree is the first
+ argument, and the right subtree is the second argument. */
+ DEMANGLE_COMPONENT_BINARY_ARGS,
+ /* A trinary expression. The left subtree is the operator, and the
+ right subtree is a TRINARY_ARG1. */
+ DEMANGLE_COMPONENT_TRINARY,
+ /* Arguments to a trinary expression. The left subtree is the first
+ argument, and the right subtree is a TRINARY_ARG2. */
+ DEMANGLE_COMPONENT_TRINARY_ARG1,
+ /* More arguments to a trinary expression. The left subtree is the
+ second argument, and the right subtree is the third argument. */
+ DEMANGLE_COMPONENT_TRINARY_ARG2,
+ /* A literal. The left subtree is the type, and the right subtree
+ is the value, represented as a DEMANGLE_COMPONENT_NAME. */
+ DEMANGLE_COMPONENT_LITERAL,
+ /* A negative literal. Like LITERAL, but the value is negated.
+ This is a minor hack: the NAME used for LITERAL points directly
+ to the mangled string, but since negative numbers are mangled
+ using 'n' instead of '-', we want a way to indicate a negative
+ number which involves neither modifying the mangled string nor
+ allocating a new copy of the literal in memory. */
+ DEMANGLE_COMPONENT_LITERAL_NEG,
+ /* A libgcj compiled resource. The left subtree is the name of the
+ resource. */
+ DEMANGLE_COMPONENT_JAVA_RESOURCE,
+ /* A name formed by the concatenation of two parts. The left
+ subtree is the first part and the right subtree the second. */
+ DEMANGLE_COMPONENT_COMPOUND_NAME,
+ /* A name formed by a single character. */
+ DEMANGLE_COMPONENT_CHARACTER,
+ /* A number. */
+ DEMANGLE_COMPONENT_NUMBER,
+ /* A decltype type. */
+ DEMANGLE_COMPONENT_DECLTYPE,
+ /* Global constructors keyed to name. */
+ DEMANGLE_COMPONENT_GLOBAL_CONSTRUCTORS,
+ /* Global destructors keyed to name. */
+ DEMANGLE_COMPONENT_GLOBAL_DESTRUCTORS,
+ /* A lambda closure type. */
+ DEMANGLE_COMPONENT_LAMBDA,
+ /* A default argument scope. */
+ DEMANGLE_COMPONENT_DEFAULT_ARG,
+ /* An unnamed type. */
+ DEMANGLE_COMPONENT_UNNAMED_TYPE,
+ /* A transactional clone. This has one subtree, the encoding for
+ which it is providing alternative linkage. */
+ DEMANGLE_COMPONENT_TRANSACTION_CLONE,
+ /* A non-transactional clone entry point. In the i386/x86_64 abi,
+ the unmangled symbol of a tm_callable becomes a thunk and the
+ non-transactional function version is mangled thus. */
+ DEMANGLE_COMPONENT_NONTRANSACTION_CLONE,
+ /* A pack expansion. */
+ DEMANGLE_COMPONENT_PACK_EXPANSION,
+ /* A name with an ABI tag. */
+ DEMANGLE_COMPONENT_TAGGED_NAME,
+ /* A cloned function. */
+ DEMANGLE_COMPONENT_CLONE
+};
+
+/* Types which are only used internally. */
+
+struct demangle_operator_info;
+struct demangle_builtin_type_info;
+
+/* A node in the tree representation is an instance of a struct
+ demangle_component. Note that the field names of the struct are
+ not well protected against macros defined by the file including
+ this one. We can fix this if it ever becomes a problem. */
+
+struct demangle_component
+{
+ /* The type of this component. */
+ enum demangle_component_type type;
+
+ union
+ {
+ /* For DEMANGLE_COMPONENT_NAME. */
+ struct
+ {
+ /* A pointer to the name (which need not NULL terminated) and
+ its length. */
+ const char *s;
+ int len;
+ } s_name;
+
+ /* For DEMANGLE_COMPONENT_OPERATOR. */
+ struct
+ {
+ /* Operator. */
+ const struct demangle_operator_info *op;
+ } s_operator;
+
+ /* For DEMANGLE_COMPONENT_EXTENDED_OPERATOR. */
+ struct
+ {
+ /* Number of arguments. */
+ int args;
+ /* Name. */
+ struct demangle_component *name;
+ } s_extended_operator;
+
+ /* For DEMANGLE_COMPONENT_FIXED_TYPE. */
+ struct
+ {
+ /* The length, indicated by a C integer type name. */
+ struct demangle_component *length;
+ /* _Accum or _Fract? */
+ short accum;
+ /* Saturating or not? */
+ short sat;
+ } s_fixed;
+
+ /* For DEMANGLE_COMPONENT_CTOR. */
+ struct
+ {
+ /* Kind of constructor. */
+ enum gnu_v3_ctor_kinds kind;
+ /* Name. */
+ struct demangle_component *name;
+ } s_ctor;
+
+ /* For DEMANGLE_COMPONENT_DTOR. */
+ struct
+ {
+ /* Kind of destructor. */
+ enum gnu_v3_dtor_kinds kind;
+ /* Name. */
+ struct demangle_component *name;
+ } s_dtor;
+
+ /* For DEMANGLE_COMPONENT_BUILTIN_TYPE. */
+ struct
+ {
+ /* Builtin type. */
+ const struct demangle_builtin_type_info *type;
+ } s_builtin;
+
+ /* For DEMANGLE_COMPONENT_SUB_STD. */
+ struct
+ {
+ /* Standard substitution string. */
+ const char* string;
+ /* Length of string. */
+ int len;
+ } s_string;
+
+ /* For DEMANGLE_COMPONENT_*_PARAM. */
+ struct
+ {
+ /* Parameter index. */
+ long number;
+ } s_number;
+
+ /* For DEMANGLE_COMPONENT_CHARACTER. */
+ struct
+ {
+ int character;
+ } s_character;
+
+ /* For other types. */
+ struct
+ {
+ /* Left (or only) subtree. */
+ struct demangle_component *left;
+ /* Right subtree. */
+ struct demangle_component *right;
+ } s_binary;
+
+ struct
+ {
+ /* subtree, same place as d_left. */
+ struct demangle_component *sub;
+ /* integer. */
+ int num;
+ } s_unary_num;
+
+ } u;
+};
+
+/* People building mangled trees are expected to allocate instances of
+ struct demangle_component themselves. They can then call one of
+ the following functions to fill them in. */
+
+/* Fill in most component types with a left subtree and a right
+ subtree. Returns non-zero on success, zero on failure, such as an
+ unrecognized or inappropriate component type. */
+
+extern int
+cplus_demangle_fill_component (struct demangle_component *fill,
+ enum demangle_component_type,
+ struct demangle_component *left,
+ struct demangle_component *right);
+
+/* Fill in a DEMANGLE_COMPONENT_NAME. Returns non-zero on success,
+ zero for bad arguments. */
+
+extern int
+cplus_demangle_fill_name (struct demangle_component *fill,
+ const char *, int);
+
+/* Fill in a DEMANGLE_COMPONENT_BUILTIN_TYPE, using the name of the
+ builtin type (e.g., "int", etc.). Returns non-zero on success,
+ zero if the type is not recognized. */
+
+extern int
+cplus_demangle_fill_builtin_type (struct demangle_component *fill,
+ const char *type_name);
+
+/* Fill in a DEMANGLE_COMPONENT_OPERATOR, using the name of the
+ operator and the number of arguments which it takes (the latter is
+ used to disambiguate operators which can be both binary and unary,
+ such as '-'). Returns non-zero on success, zero if the operator is
+ not recognized. */
+
+extern int
+cplus_demangle_fill_operator (struct demangle_component *fill,
+ const char *opname, int args);
+
+/* Fill in a DEMANGLE_COMPONENT_EXTENDED_OPERATOR, providing the
+ number of arguments and the name. Returns non-zero on success,
+ zero for bad arguments. */
+
+extern int
+cplus_demangle_fill_extended_operator (struct demangle_component *fill,
+ int numargs,
+ struct demangle_component *nm);
+
+/* Fill in a DEMANGLE_COMPONENT_CTOR. Returns non-zero on success,
+ zero for bad arguments. */
+
+extern int
+cplus_demangle_fill_ctor (struct demangle_component *fill,
+ enum gnu_v3_ctor_kinds kind,
+ struct demangle_component *name);
+
+/* Fill in a DEMANGLE_COMPONENT_DTOR. Returns non-zero on success,
+ zero for bad arguments. */
+
+extern int
+cplus_demangle_fill_dtor (struct demangle_component *fill,
+ enum gnu_v3_dtor_kinds kind,
+ struct demangle_component *name);
+
+/* This function translates a mangled name into a struct
+ demangle_component tree. The first argument is the mangled name.
+ The second argument is DMGL_* options. This returns a pointer to a
+ tree on success, or NULL on failure. On success, the third
+ argument is set to a block of memory allocated by malloc. This
+ block should be passed to free when the tree is no longer
+ needed. */
+
+extern struct demangle_component *
+cplus_demangle_v3_components (const char *mangled, int options, void **mem);
+
+/* This function takes a struct demangle_component tree and returns
+ the corresponding demangled string. The first argument is DMGL_*
+ options. The second is the tree to demangle. The third is a guess
+ at the length of the demangled string, used to initially allocate
+ the return buffer. The fourth is a pointer to a size_t. On
+ success, this function returns a buffer allocated by malloc(), and
+ sets the size_t pointed to by the fourth argument to the size of
+ the allocated buffer (not the length of the returned string). On
+ failure, this function returns NULL, and sets the size_t pointed to
+ by the fourth argument to 0 for an invalid tree, or to 1 for a
+ memory allocation error. */
+
+extern char *
+cplus_demangle_print (int options,
+ const struct demangle_component *tree,
+ int estimated_length,
+ size_t *p_allocated_size);
+
+/* This function takes a struct demangle_component tree and passes back
+ a demangled string in one or more calls to a callback function.
+ The first argument is DMGL_* options. The second is the tree to
+ demangle. The third is a pointer to a callback function; on each call
+ this receives an element of the demangled string, its length, and an
+ opaque value. The fourth is the opaque value passed to the callback.
+ The callback is called once or more to return the full demangled
+ string. The demangled element string is always nul-terminated, though
+ its length is also provided for convenience. In contrast to
+ cplus_demangle_print(), this function does not allocate heap memory
+ to grow output strings (except perhaps where alloca() is implemented
+ by malloc()), and so is normally safe for use where the heap has been
+ corrupted. On success, this function returns 1; on failure, 0. */
+
+extern int
+cplus_demangle_print_callback (int options,
+ const struct demangle_component *tree,
+ demangle_callbackref callback, void *opaque);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* DEMANGLE_H */
diff --git a/SylixOS/bintools/demangle/libiberty.h b/SylixOS/bintools/demangle/libiberty.h
new file mode 100644
index 0000000..78c42eb
--- /dev/null
+++ b/SylixOS/bintools/demangle/libiberty.h
@@ -0,0 +1,686 @@
+/* Function declarations for libiberty.
+
+ Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
+ 2006, 2007, 2008, 2009, 2010, 2011, 2013 Free Software Foundation, Inc.
+
+ Note - certain prototypes declared in this header file are for
+ functions whoes implementation copyright does not belong to the
+ FSF. Those prototypes are present in this file for reference
+ purposes only and their presence in this file should not construed
+ as an indication of ownership by the FSF of the implementation of
+ those functions in any way or form whatsoever.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ Written by Cygnus Support, 1994.
+
+ The libiberty library provides a number of functions which are
+ missing on some operating systems. We do not declare those here,
+ to avoid conflicts with the system header files on operating
+ systems that do support those functions. In this file we only
+ declare those functions which are specific to libiberty. */
+
+#ifndef LIBIBERTY_H
+#define LIBIBERTY_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "ansidecl.h"
+
+/* Get a definition for size_t. */
+#include <stddef.h>
+/* Get a definition for va_list. */
+#include <stdarg.h>
+
+#include <stdio.h>
+
+/* If the OS supports it, ensure that the supplied stream is setup to
+ avoid any multi-threaded locking. Otherwise leave the FILE pointer
+ unchanged. If the stream is NULL do nothing. */
+
+extern void unlock_stream (FILE *);
+
+/* If the OS supports it, ensure that the standard I/O streams, stdin,
+ stdout and stderr are setup to avoid any multi-threaded locking.
+ Otherwise do nothing. */
+
+extern void unlock_std_streams (void);
+
+/* Open and return a FILE pointer. If the OS supports it, ensure that
+ the stream is setup to avoid any multi-threaded locking. Otherwise
+ return the FILE pointer unchanged. */
+
+extern FILE *fopen_unlocked (const char *, const char *);
+extern FILE *fdopen_unlocked (int, const char *);
+extern FILE *freopen_unlocked (const char *, const char *, FILE *);
+
+/* Build an argument vector from a string. Allocates memory using
+ malloc. Use freeargv to free the vector. */
+
+extern char **buildargv (const char *) ATTRIBUTE_MALLOC;
+
+/* Free a vector returned by buildargv. */
+
+extern void freeargv (char **);
+
+/* Duplicate an argument vector. Allocates memory using malloc. Use
+ freeargv to free the vector. */
+
+extern char **dupargv (char **) ATTRIBUTE_MALLOC;
+
+/* Expand "@file" arguments in argv. */
+
+extern void expandargv (int *, char ***);
+
+/* Write argv to an @-file, inserting necessary quoting. */
+
+extern int writeargv (char **, FILE *);
+
+/* Return the number of elements in argv. */
+
+extern int countargv (char**);
+
+/* Return the last component of a path name. Note that we can't use a
+ prototype here because the parameter is declared inconsistently
+ across different systems, sometimes as "char *" and sometimes as
+ "const char *" */
+
+/* HAVE_DECL_* is a three-state macro: undefined, 0 or 1. If it is
+ undefined, we haven't run the autoconf check so provide the
+ declaration without arguments. If it is 0, we checked and failed
+ to find the declaration so provide a fully prototyped one. If it
+ is 1, we found it so don't provide any declaration at all. */
+#if !HAVE_DECL_BASENAME
+#if defined (__GNU_LIBRARY__ ) || defined (__linux__) || defined (__FreeBSD__) || defined (__OpenBSD__) || defined(__NetBSD__) || defined (__CYGWIN__) || defined (__CYGWIN32__) || defined (__MINGW32__) || defined (HAVE_DECL_BASENAME)
+extern char *basename (const char *) ATTRIBUTE_RETURNS_NONNULL ATTRIBUTE_NONNULL(1);
+#else
+/* Do not allow basename to be used if there is no prototype seen. We
+ either need to use the above prototype or have one from
+ autoconf which would result in HAVE_DECL_BASENAME being set. */
+#define basename basename_cannot_be_used_without_a_prototype
+#endif
+#endif
+
+/* A well-defined basename () that is always compiled in. */
+
+extern const char *lbasename (const char *) ATTRIBUTE_RETURNS_NONNULL ATTRIBUTE_NONNULL(1);
+
+/* Same, but assumes DOS semantics (drive name, backslash is also a
+ dir separator) regardless of host. */
+
+extern const char *dos_lbasename (const char *) ATTRIBUTE_RETURNS_NONNULL ATTRIBUTE_NONNULL(1);
+
+/* Same, but assumes Unix semantics (absolute paths always start with
+ a slash, only forward slash is accepted as dir separator)
+ regardless of host. */
+
+extern const char *unix_lbasename (const char *) ATTRIBUTE_RETURNS_NONNULL ATTRIBUTE_NONNULL(1);
+
+/* A well-defined realpath () that is always compiled in. */
+
+extern char *lrealpath (const char *);
+
+/* Concatenate an arbitrary number of strings. You must pass NULL as
+ the last argument of this function, to terminate the list of
+ strings. Allocates memory using xmalloc. */
+
+extern char *concat (const char *, ...) ATTRIBUTE_MALLOC ATTRIBUTE_RETURNS_NONNULL ATTRIBUTE_SENTINEL;
+
+/* Concatenate an arbitrary number of strings. You must pass NULL as
+ the last argument of this function, to terminate the list of
+ strings. Allocates memory using xmalloc. The first argument is
+ not one of the strings to be concatenated, but if not NULL is a
+ pointer to be freed after the new string is created, similar to the
+ way xrealloc works. */
+
+extern char *reconcat (char *, const char *, ...) ATTRIBUTE_MALLOC ATTRIBUTE_RETURNS_NONNULL ATTRIBUTE_SENTINEL;
+
+/* Determine the length of concatenating an arbitrary number of
+ strings. You must pass NULL as the last argument of this function,
+ to terminate the list of strings. */
+
+extern unsigned long concat_length (const char *, ...) ATTRIBUTE_SENTINEL;
+
+/* Concatenate an arbitrary number of strings into a SUPPLIED area of
+ memory. You must pass NULL as the last argument of this function,
+ to terminate the list of strings. The supplied memory is assumed
+ to be large enough. */
+
+extern char *concat_copy (char *, const char *, ...) ATTRIBUTE_RETURNS_NONNULL ATTRIBUTE_NONNULL(1) ATTRIBUTE_SENTINEL;
+
+/* Concatenate an arbitrary number of strings into a GLOBAL area of
+ memory. You must pass NULL as the last argument of this function,
+ to terminate the list of strings. The supplied memory is assumed
+ to be large enough. */
+
+extern char *concat_copy2 (const char *, ...) ATTRIBUTE_RETURNS_NONNULL ATTRIBUTE_SENTINEL;
+
+/* This is the global area used by concat_copy2. */
+
+extern char *libiberty_concat_ptr;
+
+/* Concatenate an arbitrary number of strings. You must pass NULL as
+ the last argument of this function, to terminate the list of
+ strings. Allocates memory using alloca. The arguments are
+ evaluated twice! */
+#define ACONCAT(ACONCAT_PARAMS) \
+ (libiberty_concat_ptr = (char *) alloca (concat_length ACONCAT_PARAMS + 1), \
+ concat_copy2 ACONCAT_PARAMS)
+
+/* Check whether two file descriptors refer to the same file. */
+
+extern int fdmatch (int fd1, int fd2);
+
+/* Return the position of the first bit set in the argument. */
+/* Prototypes vary from system to system, so we only provide a
+ prototype on systems where we know that we need it. */
+#if defined (HAVE_DECL_FFS) && !HAVE_DECL_FFS
+extern int ffs(int);
+#endif
+
+/* Get the working directory. The result is cached, so don't call
+ chdir() between calls to getpwd(). */
+
+extern char * getpwd (void);
+
+/* Get the current time. */
+/* Prototypes vary from system to system, so we only provide a
+ prototype on systems where we know that we need it. */
+#ifdef __MINGW32__
+/* Forward declaration to avoid #include <sys/time.h>. */
+struct timeval;
+extern int gettimeofday (struct timeval *, void *);
+#endif
+
+/* Get the amount of time the process has run, in microseconds. */
+
+extern long get_run_time (void);
+
+/* Generate a relocated path to some installation directory. Allocates
+ return value using malloc. */
+
+extern char *make_relative_prefix (const char *, const char *,
+ const char *) ATTRIBUTE_MALLOC;
+
+/* Generate a relocated path to some installation directory without
+ attempting to follow any soft links. Allocates
+ return value using malloc. */
+
+extern char *make_relative_prefix_ignore_links (const char *, const char *,
+ const char *) ATTRIBUTE_MALLOC;
+
+/* Choose a temporary directory to use for scratch files. */
+
+extern char *choose_temp_base (void) ATTRIBUTE_MALLOC ATTRIBUTE_RETURNS_NONNULL;
+
+/* Return a temporary file name or NULL if unable to create one. */
+
+extern char *make_temp_file (const char *) ATTRIBUTE_MALLOC;
+
+/* Remove a link to a file unless it is special. */
+
+extern int unlink_if_ordinary (const char *);
+
+/* Allocate memory filled with spaces. Allocates using malloc. */
+
+extern const char *spaces (int count);
+
+/* Return the maximum error number for which strerror will return a
+ string. */
+
+extern int errno_max (void);
+
+/* Return the name of an errno value (e.g., strerrno (EINVAL) returns
+ "EINVAL"). */
+
+extern const char *strerrno (int);
+
+/* Given the name of an errno value, return the value. */
+
+extern int strtoerrno (const char *);
+
+/* ANSI's strerror(), but more robust. */
+
+extern char *xstrerror (int) ATTRIBUTE_RETURNS_NONNULL;
+
+/* Return the maximum signal number for which strsignal will return a
+ string. */
+
+extern int signo_max (void);
+
+/* Return a signal message string for a signal number
+ (e.g., strsignal (SIGHUP) returns something like "Hangup"). */
+/* This is commented out as it can conflict with one in system headers.
+ We still document its existence though. */
+
+/*extern const char *strsignal (int);*/
+
+/* Return the name of a signal number (e.g., strsigno (SIGHUP) returns
+ "SIGHUP"). */
+
+extern const char *strsigno (int);
+
+/* Given the name of a signal, return its number. */
+
+extern int strtosigno (const char *);
+
+/* Register a function to be run by xexit. Returns 0 on success. */
+
+extern int xatexit (void (*fn) (void));
+
+/* Exit, calling all the functions registered with xatexit. */
+
+extern void xexit (int status) ATTRIBUTE_NORETURN;
+
+/* Set the program name used by xmalloc. */
+
+extern void xmalloc_set_program_name (const char *);
+
+/* Report an allocation failure. */
+extern void xmalloc_failed (size_t) ATTRIBUTE_NORETURN;
+
+/* Allocate memory without fail. If malloc fails, this will print a
+ message to stderr (using the name set by xmalloc_set_program_name,
+ if any) and then call xexit. */
+
+extern void *xmalloc (size_t) ATTRIBUTE_MALLOC ATTRIBUTE_RETURNS_NONNULL;
+
+/* Reallocate memory without fail. This works like xmalloc. Note,
+ realloc type functions are not suitable for attribute malloc since
+ they may return the same address across multiple calls. */
+
+extern void *xrealloc (void *, size_t) ATTRIBUTE_RETURNS_NONNULL;
+
+/* Allocate memory without fail and set it to zero. This works like
+ xmalloc. */
+
+extern void *xcalloc (size_t, size_t) ATTRIBUTE_MALLOC ATTRIBUTE_RETURNS_NONNULL;
+
+/* Copy a string into a memory buffer without fail. */
+
+extern char *xstrdup (const char *) ATTRIBUTE_MALLOC ATTRIBUTE_RETURNS_NONNULL;
+
+/* Copy at most N characters from string into a buffer without fail. */
+
+extern char *xstrndup (const char *, size_t) ATTRIBUTE_MALLOC ATTRIBUTE_RETURNS_NONNULL;
+
+/* Copy an existing memory buffer to a new memory buffer without fail. */
+
+extern void *xmemdup (const void *, size_t, size_t) ATTRIBUTE_MALLOC ATTRIBUTE_RETURNS_NONNULL;
+
+/* Physical memory routines. Return values are in BYTES. */
+extern double physmem_total (void);
+extern double physmem_available (void);
+
+/* Compute the 32-bit CRC of a block of memory. */
+extern unsigned int xcrc32 (const unsigned char *, int, unsigned int);
+
+/* These macros provide a K&R/C89/C++-friendly way of allocating structures
+ with nice encapsulation. The XDELETE*() macros are technically
+ superfluous, but provided here for symmetry. Using them consistently
+ makes it easier to update client code to use different allocators such
+ as new/delete and new[]/delete[]. */
+
+/* Scalar allocators. */
+
+#define XALLOCA(T) ((T *) alloca (sizeof (T)))
+#define XNEW(T) ((T *) xmalloc (sizeof (T)))
+#define XCNEW(T) ((T *) xcalloc (1, sizeof (T)))
+#define XDUP(T, P) ((T *) xmemdup ((P), sizeof (T), sizeof (T)))
+#define XDELETE(P) free ((void*) (P))
+
+/* Array allocators. */
+
+#define XALLOCAVEC(T, N) ((T *) alloca (sizeof (T) * (N)))
+#define XNEWVEC(T, N) ((T *) xmalloc (sizeof (T) * (N)))
+#define XCNEWVEC(T, N) ((T *) xcalloc ((N), sizeof (T)))
+#define XDUPVEC(T, P, N) ((T *) xmemdup ((P), sizeof (T) * (N), sizeof (T) * (N)))
+#define XRESIZEVEC(T, P, N) ((T *) xrealloc ((void *) (P), sizeof (T) * (N)))
+#define XDELETEVEC(P) free ((void*) (P))
+
+/* Allocators for variable-sized structures and raw buffers. */
+
+#define XALLOCAVAR(T, S) ((T *) alloca ((S)))
+#define XNEWVAR(T, S) ((T *) xmalloc ((S)))
+#define XCNEWVAR(T, S) ((T *) xcalloc (1, (S)))
+#define XDUPVAR(T, P, S1, S2) ((T *) xmemdup ((P), (S1), (S2)))
+#define XRESIZEVAR(T, P, S) ((T *) xrealloc ((P), (S)))
+
+/* Type-safe obstack allocator. */
+
+#define XOBNEW(O, T) ((T *) obstack_alloc ((O), sizeof (T)))
+#define XOBNEWVEC(O, T, N) ((T *) obstack_alloc ((O), sizeof (T) * (N)))
+#define XOBNEWVAR(O, T, S) ((T *) obstack_alloc ((O), (S)))
+#define XOBFINISH(O, T) ((T) obstack_finish ((O)))
+
+/* hex character manipulation routines */
+
+#define _hex_array_size 256
+#define _hex_bad 99
+extern const unsigned char _hex_value[_hex_array_size];
+extern void hex_init (void);
+#define hex_p(c) (hex_value (c) != _hex_bad)
+/* If you change this, note well: Some code relies on side effects in
+ the argument being performed exactly once. */
+#define hex_value(c) ((unsigned int) _hex_value[(unsigned char) (c)])
+
+/* Flags for pex_init. These are bits to be or'ed together. */
+
+/* Record subprocess times, if possible. */
+#define PEX_RECORD_TIMES 0x1
+
+/* Use pipes for communication between processes, if possible. */
+#define PEX_USE_PIPES 0x2
+
+/* Save files used for communication between processes. */
+#define PEX_SAVE_TEMPS 0x4
+
+/* Prepare to execute one or more programs, with standard output of
+ each program fed to standard input of the next.
+ FLAGS As above.
+ PNAME The name of the program to report in error messages.
+ TEMPBASE A base name to use for temporary files; may be NULL to
+ use a random name.
+ Returns NULL on error. */
+
+extern struct pex_obj *pex_init (int flags, const char *pname,
+ const char *tempbase) ATTRIBUTE_RETURNS_NONNULL;
+
+/* Flags for pex_run. These are bits to be or'ed together. */
+
+/* Last program in pipeline. Standard output of program goes to
+ OUTNAME, or, if OUTNAME is NULL, to standard output of caller. Do
+ not set this if you want to call pex_read_output. After this is
+ set, pex_run may no longer be called with the same struct
+ pex_obj. */
+#define PEX_LAST 0x1
+
+/* Search for program in executable search path. */
+#define PEX_SEARCH 0x2
+
+/* OUTNAME is a suffix. */
+#define PEX_SUFFIX 0x4
+
+/* Send program's standard error to standard output. */
+#define PEX_STDERR_TO_STDOUT 0x8
+
+/* Input file should be opened in binary mode. This flag is ignored
+ on Unix. */
+#define PEX_BINARY_INPUT 0x10
+
+/* Output file should be opened in binary mode. This flag is ignored
+ on Unix. For proper behaviour PEX_BINARY_INPUT and
+ PEX_BINARY_OUTPUT have to match appropriately--i.e., a call using
+ PEX_BINARY_OUTPUT should be followed by a call using
+ PEX_BINARY_INPUT. */
+#define PEX_BINARY_OUTPUT 0x20
+
+/* Capture stderr to a pipe. The output can be read by
+ calling pex_read_err and reading from the returned
+ FILE object. This flag may be specified only for
+ the last program in a pipeline.
+
+ This flag is supported only on Unix and Windows. */
+#define PEX_STDERR_TO_PIPE 0x40
+
+/* Capture stderr in binary mode. This flag is ignored
+ on Unix. */
+#define PEX_BINARY_ERROR 0x80
+
+
+/* Execute one program. Returns NULL on success. On error returns an
+ error string (typically just the name of a system call); the error
+ string is statically allocated.
+
+ OBJ Returned by pex_init.
+
+ FLAGS As above.
+
+ EXECUTABLE The program to execute.
+
+ ARGV NULL terminated array of arguments to pass to the program.
+
+ OUTNAME Sets the output file name as follows:
+
+ PEX_SUFFIX set (OUTNAME may not be NULL):
+ TEMPBASE parameter to pex_init not NULL:
+ Output file name is the concatenation of TEMPBASE
+ and OUTNAME.
+ TEMPBASE is NULL:
+ Output file name is a random file name ending in
+ OUTNAME.
+ PEX_SUFFIX not set:
+ OUTNAME not NULL:
+ Output file name is OUTNAME.
+ OUTNAME NULL, TEMPBASE not NULL:
+ Output file name is randomly chosen using
+ TEMPBASE.
+ OUTNAME NULL, TEMPBASE NULL:
+ Output file name is randomly chosen.
+
+ If PEX_LAST is not set, the output file name is the
+ name to use for a temporary file holding stdout, if
+ any (there will not be a file if PEX_USE_PIPES is set
+ and the system supports pipes). If a file is used, it
+ will be removed when no longer needed unless
+ PEX_SAVE_TEMPS is set.
+
+ If PEX_LAST is set, and OUTNAME is not NULL, standard
+ output is written to the output file name. The file
+ will not be removed. If PEX_LAST and PEX_SUFFIX are
+ both set, TEMPBASE may not be NULL.
+
+ ERRNAME If not NULL, this is the name of a file to which
+ standard error is written. If NULL, standard error of
+ the program is standard error of the caller.
+
+ ERR On an error return, *ERR is set to an errno value, or
+ to 0 if there is no relevant errno.
+*/
+
+extern const char *pex_run (struct pex_obj *obj, int flags,
+ const char *executable, char * const *argv,
+ const char *outname, const char *errname,
+ int *err);
+
+/* As for pex_run (), but takes an extra parameter to enable the
+ environment for the child process to be specified.
+
+ ENV The environment for the child process, specified as
+ an array of character pointers. Each element of the
+ array should point to a string of the form VAR=VALUE,
+ with the exception of the last element which must be
+ a null pointer.
+*/
+
+extern const char *pex_run_in_environment (struct pex_obj *obj, int flags,
+ const char *executable,
+ char * const *argv,
+ char * const *env,
+ const char *outname,
+ const char *errname, int *err);
+
+/* Return a stream for a temporary file to pass to the first program
+ in the pipeline as input. The file name is chosen as for pex_run.
+ pex_run closes the file automatically; don't close it yourself. */
+
+extern FILE *pex_input_file (struct pex_obj *obj, int flags,
+ const char *in_name);
+
+/* Return a stream for a pipe connected to the standard input of the
+ first program in the pipeline. You must have passed
+ `PEX_USE_PIPES' to `pex_init'. Close the returned stream
+ yourself. */
+
+extern FILE *pex_input_pipe (struct pex_obj *obj, int binary);
+
+/* Read the standard output of the last program to be executed.
+ pex_run can not be called after this. BINARY should be non-zero if
+ the file should be opened in binary mode; this is ignored on Unix.
+ Returns NULL on error. Don't call fclose on the returned FILE; it
+ will be closed by pex_free. */
+
+extern FILE *pex_read_output (struct pex_obj *, int binary);
+
+/* Read the standard error of the last program to be executed.
+ pex_run can not be called after this. BINARY should be non-zero if
+ the file should be opened in binary mode; this is ignored on Unix.
+ Returns NULL on error. Don't call fclose on the returned FILE; it
+ will be closed by pex_free. */
+
+extern FILE *pex_read_err (struct pex_obj *, int binary);
+
+/* Return exit status of all programs in VECTOR. COUNT indicates the
+ size of VECTOR. The status codes in the vector are in the order of
+ the calls to pex_run. Returns 0 on error, 1 on success. */
+
+extern int pex_get_status (struct pex_obj *, int count, int *vector);
+
+/* Return times of all programs in VECTOR. COUNT indicates the size
+ of VECTOR. struct pex_time is really just struct timeval, but that
+ is not portable to all systems. Returns 0 on error, 1 on
+ success. */
+
+struct pex_time
+{
+ unsigned long user_seconds;
+ unsigned long user_microseconds;
+ unsigned long system_seconds;
+ unsigned long system_microseconds;
+};
+
+extern int pex_get_times (struct pex_obj *, int count,
+ struct pex_time *vector);
+
+/* Clean up a pex_obj. If you have not called pex_get_times or
+ pex_get_status, this will try to kill the subprocesses. */
+
+extern void pex_free (struct pex_obj *);
+
+/* Just execute one program. Return value is as for pex_run.
+ FLAGS Combination of PEX_SEARCH and PEX_STDERR_TO_STDOUT.
+ EXECUTABLE As for pex_run.
+ ARGV As for pex_run.
+ PNAME As for pex_init.
+ OUTNAME As for pex_run when PEX_LAST is set.
+ ERRNAME As for pex_run.
+ STATUS Set to exit status on success.
+ ERR As for pex_run.
+*/
+
+extern const char *pex_one (int flags, const char *executable,
+ char * const *argv, const char *pname,
+ const char *outname, const char *errname,
+ int *status, int *err);
+
+/* pexecute and pwait are the old pexecute interface, still here for
+ backward compatibility. Don't use these for new code. Instead,
+ use pex_init/pex_run/pex_get_status/pex_free, or pex_one. */
+
+/* Definitions used by the pexecute routine. */
+
+#define PEXECUTE_FIRST 1
+#define PEXECUTE_LAST 2
+#define PEXECUTE_ONE (PEXECUTE_FIRST + PEXECUTE_LAST)
+#define PEXECUTE_SEARCH 4
+#define PEXECUTE_VERBOSE 8
+
+/* Execute a program. */
+
+extern int pexecute (const char *, char * const *, const char *,
+ const char *, char **, char **, int);
+
+/* Wait for pexecute to finish. */
+
+extern int pwait (int, int *, int);
+
+#if !HAVE_DECL_ASPRINTF
+/* Like sprintf but provides a pointer to malloc'd storage, which must
+ be freed by the caller. */
+
+extern int asprintf (char **, const char *, ...) ATTRIBUTE_PRINTF_2;
+#endif
+
+#if !HAVE_DECL_VASPRINTF
+/* Like vsprintf but provides a pointer to malloc'd storage, which
+ must be freed by the caller. */
+
+extern int vasprintf (char **, const char *, va_list) ATTRIBUTE_PRINTF(2,0);
+#endif
+
+#if defined(HAVE_DECL_SNPRINTF) && !HAVE_DECL_SNPRINTF
+/* Like sprintf but prints at most N characters. */
+extern int snprintf (char *, size_t, const char *, ...) ATTRIBUTE_PRINTF_3;
+#endif
+
+#if defined(HAVE_DECL_VSNPRINTF) && !HAVE_DECL_VSNPRINTF
+/* Like vsprintf but prints at most N characters. */
+extern int vsnprintf (char *, size_t, const char *, va_list) ATTRIBUTE_PRINTF(3,0);
+#endif
+
+#if defined(HAVE_DECL_STRVERSCMP) && !HAVE_DECL_STRVERSCMP
+/* Compare version strings. */
+extern int strverscmp (const char *, const char *);
+#endif
+
+/* Set the title of a process */
+extern void setproctitle (const char *name, ...);
+
+/* Increase stack limit if possible. */
+extern void stack_limit_increase (unsigned long);
+
+#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0]))
+
+/* Drastically simplified alloca configurator. If we're using GCC,
+ we use __builtin_alloca; otherwise we use the C alloca. The C
+ alloca is always available. You can override GCC by defining
+ USE_C_ALLOCA yourself. The canonical autoconf macro C_ALLOCA is
+ also set/unset as it is often used to indicate whether code needs
+ to call alloca(0). */
+extern void *C_alloca (size_t) ATTRIBUTE_MALLOC;
+#undef alloca
+#if GCC_VERSION >= 2000 && !defined USE_C_ALLOCA
+# define alloca(x) __builtin_alloca(x)
+# undef C_ALLOCA
+# define ASTRDUP(X) \
+ (__extension__ ({ const char *const libiberty_optr = (X); \
+ const unsigned long libiberty_len = strlen (libiberty_optr) + 1; \
+ char *const libiberty_nptr = (char *const) alloca (libiberty_len); \
+ (char *) memcpy (libiberty_nptr, libiberty_optr, libiberty_len); }))
+#else
+# define alloca(x) C_alloca(x)
+# undef USE_C_ALLOCA
+# define USE_C_ALLOCA 1
+# undef C_ALLOCA
+# define C_ALLOCA 1
+extern const char *libiberty_optr;
+extern char *libiberty_nptr;
+extern unsigned long libiberty_len;
+# define ASTRDUP(X) \
+ (libiberty_optr = (X), \
+ libiberty_len = strlen (libiberty_optr) + 1, \
+ libiberty_nptr = (char *) alloca (libiberty_len), \
+ (char *) memcpy (libiberty_nptr, libiberty_optr, libiberty_len))
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* ! defined (LIBIBERTY_H) */
diff --git a/SylixOS/config/cpu/cpu_cfg_csky.h b/SylixOS/config/cpu/cpu_cfg_csky.h
index 4dc4611..1cd8566 100644
--- a/SylixOS/config/cpu/cpu_cfg_csky.h
+++ b/SylixOS/config/cpu/cpu_cfg_csky.h
@@ -104,6 +104,12 @@
*********************************************************************************************************/
#define LW_CFG_CPU_FPU_EN 1 /* CPU 是否拥有 FPU */
+#define LW_CFG_CPU_FPU_IDE 0 /* FPU 是否使能非规格化数异常 */
+#define LW_CFG_CPU_FPU_IXE 0 /* FPU 是否使能非精确异常 */
+#define LW_CFG_CPU_FPU_UFE 0 /* FPU 是否使能下溢异常 */
+#define LW_CFG_CPU_FPU_OFE 0 /* FPU 是否使能上溢异常 */
+#define LW_CFG_CPU_FPU_DZE 0 /* FPU 是否使能除 0 异常 */
+#define LW_CFG_CPU_FPU_IOE 0 /* FPU 是否使能非法操作异常 */
/*********************************************************************************************************
DSP 数字信号处理器
diff --git a/SylixOS/config/cpu/cpu_cfg_ppc.h b/SylixOS/config/cpu/cpu_cfg_ppc.h
index e95b852..4d2078f 100644
--- a/SylixOS/config/cpu/cpu_cfg_ppc.h
+++ b/SylixOS/config/cpu/cpu_cfg_ppc.h
@@ -53,7 +53,7 @@
PowerPC 配置
*********************************************************************************************************/
-#define LW_CFG_PPC_CACHE_L2 0 /* 是否允许管理 PPC 二级 CACHE */
+#define LW_CFG_PPC_CACHE_L2 1 /* 是否允许管理 PPC 二级 CACHE */
/*********************************************************************************************************
浮点运算单元
@@ -65,7 +65,7 @@
DSP 数字信号处理器
*********************************************************************************************************/
-#define LW_CFG_CPU_DSP_EN 0 /* CPU 是否拥有 DSP */
+#define LW_CFG_CPU_DSP_EN 1 /* CPU 是否拥有 DSP */
/*********************************************************************************************************
ATOMIC
diff --git a/SylixOS/config/driver/drv_cfg.h b/SylixOS/config/driver/drv_cfg.h
index 743e85f..4acd5ef 100644
--- a/SylixOS/config/driver/drv_cfg.h
+++ b/SylixOS/config/driver/drv_cfg.h
@@ -29,7 +29,7 @@
2: TTY 设备
*********************************************************************************************************/
-#define LW_CFG_DRV_SIO_16C550 0 /* 16C550 串口驱动使能 */
+#define LW_CFG_DRV_SIO_16C550 1 /* 16C550 串口驱动使能 */
/*********************************************************************************************************
* CAN 设备驱动
@@ -46,7 +46,7 @@
* 依存关系: 无
*********************************************************************************************************/
-#define LW_CFG_DRV_INT_I8259A 0 /* Intel 8259A 驱动使能 */
+#define LW_CFG_DRV_INT_I8259A 1 /* Intel 8259A 驱动使能 */
/*********************************************************************************************************
* 定时器驱动
@@ -54,7 +54,7 @@
* 依存关系: 无
*********************************************************************************************************/
-#define LW_CFG_DRV_TIMER_I8254 0 /* Intel 8254 驱动使能 */
+#define LW_CFG_DRV_TIMER_I8254 1 /* Intel 8254 驱动使能 */
/*********************************************************************************************************
* 存储器接口驱动
diff --git a/SylixOS/config/mp/mp_cfg.h b/SylixOS/config/mp/mp_cfg.h
index d5e04ba..5e0d8e1 100644
--- a/SylixOS/config/mp/mp_cfg.h
+++ b/SylixOS/config/mp/mp_cfg.h
@@ -44,7 +44,7 @@
* 注 意 : SMP 同构多处理器支持, 将多核处理器在应用层面抽象为一个逻辑单核接口.
*********************************************************************************************************/
-#define LW_CFG_SMP_EN 0 /* 是否需要系统对多处理器支持 */
+#define LW_CFG_SMP_EN 1 /* 是否需要系统对多处理器支持 */
#define LW_CFG_SMP_CPU_DOWN_EN 0 /* 是否支持动态关闭 CPU (不推荐使用) */
#define LW_CFG_SMP_REVERSE_FOREACH 0 /* CPU 遍历时从最大的 CPU 开始 */
#define LW_CFG_MAX_PROCESSORS 32 /* 系统支持 SMP 处理器最大个数, 1 ~ 2048 */
@@ -55,7 +55,7 @@
* 注 意 : MPI 多操作系统并行计算系统通信层抽象
*********************************************************************************************************/
-#define LW_CFG_MPI_EN 0 /* 并行分布式计算系统支持 */
+#define LW_CFG_MPI_EN 1 /* 并行分布式计算系统支持 */
#define LW_CFG_PROCESSOR_NUMBER 1 /* 当前 MPI 处理器号 */
#define LW_CFG_MAX_MPDPMAS 2 /* 系统双通道 RAM 缓冲区个数 < 65535 */
diff --git a/SylixOS/config/net/net_cfg.h b/SylixOS/config/net/net_cfg.h
index a4d7d30..e7320a6 100644
--- a/SylixOS/config/net/net_cfg.h
+++ b/SylixOS/config/net/net_cfg.h
@@ -23,7 +23,7 @@
#define __NET_CFG_H
/*********************************************************************************************************
-* 基本参数
+* 裁剪配置
* 依存关系: 1: 定长分区内存管理
* 2: 互斥信号量
* 3: 二值信号量
@@ -33,8 +33,8 @@
*********************************************************************************************************/
#define LW_CFG_NET_EN 1 /* 是否允许网络功能 */
-#define LW_CFG_NET_ROUTER 0 /* 配置为路由器模式 */
-#define LW_CFG_NET_MROUTER 0 /* 配置为支持组播路由模式 */
+#define LW_CFG_NET_ROUTER 1 /* 配置为路由器模式 */
+#define LW_CFG_NET_MROUTER 1 /* 配置为支持组播路由模式 */
#define LW_CFG_NET_BALANCING 1 /* 源地址流量均衡路由支持 */
#define LW_CFG_NET_IPV6 1 /* 是否使能 IPv6 协议支持 */
diff --git a/SylixOS/config/net/net_perf_cfg.h b/SylixOS/config/net/net_perf_cfg.h
index 87d280e..e137e9d 100644
--- a/SylixOS/config/net/net_perf_cfg.h
+++ b/SylixOS/config/net/net_perf_cfg.h
@@ -66,9 +66,10 @@
缓存方法 (tlsf 可以提高协议栈吞吐率, 但其使用的任务级 spinlock 会稍微影响任务抢占延迟)
*********************************************************************************************************/
-#define LW_CFG_LWIP_MEM_TLSF 1 /* 是否使用 tlfs 进行内存分配 */
+#define LW_CFG_LWIP_MEM_TLSF 1 /* 是否使用 tlsf 进行内存分配 */
#define LW_CFG_LWIP_MEM_TLSF_BRK 1 /* 是否允许内存扩展 */
#define LW_CFG_LWIP_MEM_TLSF_BRK_TIMES 1 /* 内存扩展倍数 */
+#define LW_CFG_LWIP_MEM_TLSF_ASSERT 0 /* 是否需要 tlsf 断言 */
/*********************************************************************************************************
流控配置
diff --git a/SylixOS/config/system/system_cfg.h b/SylixOS/config/system/system_cfg.h
index ef546b9..5677367 100644
--- a/SylixOS/config/system/system_cfg.h
+++ b/SylixOS/config/system/system_cfg.h
@@ -372,7 +372,7 @@
2: 消息队列
*********************************************************************************************************/
-#define LW_CFG_HOTPLUG_EN 0 /* 是否允许系统提供热插拔消息支持 */
+#define LW_CFG_HOTPLUG_EN 1 /* 是否允许系统提供热插拔消息支持 */
#define LW_CFG_HOTPLUG_OPTION LW_OPTION_THREAD_STK_CHK
/* 热插拔消息服务线程选项 */
#define LW_CFG_HOTPLUG_MAX_MSGS 8 /* 最大并发消息数量(即系统可缓冲的消息数量) */
diff --git a/SylixOS/driver/can/sja1000.c b/SylixOS/driver/can/sja1000.c
index d3cb6d4..4bc501e 100644
--- a/SylixOS/driver/can/sja1000.c
+++ b/SylixOS/driver/can/sja1000.c
@@ -700,6 +700,15 @@ static INT sja1000Ioctl (SJA1000_CHAN *pcanchan, INT cmd, LONG arg)
sja1000TxStartup(pcanchan);
break;
+ case CAN_DEV_GET_DEV_ECC_CODE: /* 获取错误代码捕捉寄存器的值 */
+ mode = GET_REG(pcanchan, ECC);
+ *(UINT8 *)arg = mode;
+ break;
+
+ case CAN_DEV_GET_DEV_IDT_CODE: /* 获取仲裁丢失捕捉寄存器的值 */
+ mode = GET_REG(pcanchan, ALC);
+ *(UINT8 *)arg = mode;
+
case SJA1000_SET_FLITER: /* sja1000 filter */
if (arg) {
SJA1000_FILTER *pfilter = (SJA1000_FILTER *)arg;
diff --git a/SylixOS/hosttools/makelitesymbol/makelitesymbol.bat b/SylixOS/hosttools/makelitesymbol/makelitesymbol.bat
index 62b6a34..bf1c9d7 100644
--- a/SylixOS/hosttools/makelitesymbol/makelitesymbol.bat
+++ b/SylixOS/hosttools/makelitesymbol/makelitesymbol.bat
@@ -28,7 +28,6 @@ for /f "tokens=1,3 delims= " %%i in (func.txt) do @(
set /a num+=1
)
-
for /f "tokens=1,3 delims= " %%i in (obj.txt) do @(
echo %%j = 0x%%i; >> %destfile%
set /a num+=1
diff --git a/SylixOS/hosttools/makesymbol/makesymbol.bat b/SylixOS/hosttools/makesymbol/makesymbol.bat
index c66a90b..2b938f3 100644
--- a/SylixOS/hosttools/makesymbol/makesymbol.bat
+++ b/SylixOS/hosttools/makesymbol/makesymbol.bat
@@ -186,6 +186,7 @@ echo #ifdef SYLIXOS_EXPORT_KSYMBOL >> symbol.c
for /f "tokens=3 delims= " %%i in (func.txt) do @(
if not "%%i"=="__sylixos_version" (
echo extern int %%i^(^); >> symbol.c
+ echo -Wl,--ignore-unresolved-symbol,%%i >> symbol.ld
set /a num+=1
)
)
@@ -193,6 +194,7 @@ for /f "tokens=3 delims= " %%i in (func.txt) do @(
for /f "tokens=3 delims= " %%i in (obj.txt) do @(
if not "%%i"=="__sylixos_version" (
echo extern int %%i; >> symbol.c
+ echo -Wl,--ignore-unresolved-symbol,%%i >> symbol.ld
set /a num+=1
)
)
@@ -270,4 +272,4 @@ echo ***************************************************************************
del func.txt
del obj.txt
-@echo on
+@echo on \ No newline at end of file
diff --git a/SylixOS/hosttools/makesymbol/makesymbol.sh b/SylixOS/hosttools/makesymbol/makesymbol.sh
index a699ee8..d167999 100644
--- a/SylixOS/hosttools/makesymbol/makesymbol.sh
+++ b/SylixOS/hosttools/makesymbol/makesymbol.sh
@@ -3,6 +3,7 @@
srcfile=libsylixos.a
symbolc=symbol.c
symbolh=symbol.h
+symbolld=symbol.ld
NM=nm
funcfile=func.lst
objsfile=objs.lst
diff --git a/SylixOS/include/arch/csky/inc/cskyregs.h b/SylixOS/include/arch/csky/inc/cskyregs.h
index 39283e4..286ae9d 100644
--- a/SylixOS/include/arch/csky/inc/cskyregs.h
+++ b/SylixOS/include/arch/csky/inc/cskyregs.h
@@ -267,12 +267,14 @@ static inline uint32_t cskyMpuGetPRSR(void)
#define TLBWI_TLB 0x20000000
-#define IDE_STAT (1 << 5)
-#define IXE_STAT (1 << 4)
-#define UFE_STAT (1 << 3)
-#define OFE_STAT (1 << 2)
-#define DZE_STAT (1 << 1)
-#define IOE_STAT (1 << 0)
+#define FESR_ILLE (1 << 16)
+#define FESR_FEC (1 << 7)
+#define FESR_IDC (1 << 5)
+#define FESR_IXC (1 << 4)
+#define FESR_UFC (1 << 3)
+#define FESR_OFC (1 << 2)
+#define FESR_DZC (1 << 1)
+#define FESR_IOC (1 << 0)
#endif /* __CSKY_REGS_H */
/*********************************************************************************************************
diff --git a/SylixOS/include/linux/compat.h b/SylixOS/include/linux/compat.h
index 9f09682..a081c49 100644
--- a/SylixOS/include/linux/compat.h
+++ b/SylixOS/include/linux/compat.h
@@ -183,9 +183,20 @@ static LW_INLINE void *kmalloc (size_t size, int flags)
#define max_t(type, x, y) \
({ type __x = (x); type __y = (y); __x > __y ? __x: __y; })
+/*
+ * BUG, BUG_ON, WARN, WARN_ON, ...
+ */
+#ifdef printk
+#define __WARN_printf(arg...) do { printk(arg); } while (0)
+#elif LW_CFG_FIO_LIB_EN > 0
+#define __WARN_printf(arg...) do { fprintf(stderr, arg); } while (0)
+#else
+#define __WARN_printf(arg...) do { _PrintFormat(arg); } while (0)
+#endif
+
#ifndef BUG
#define BUG() do { \
- printf("BUG at %s:%d!\n", __FILE__, __LINE__); \
+ __WARN_printf("BUG at %s:%d!\n", __FILE__, __LINE__); \
} while (0)
#define BUG_ON(condition) do { if (condition) BUG(); } while(0)
@@ -195,7 +206,7 @@ static LW_INLINE void *kmalloc (size_t size, int flags)
#define WARN(condition, format...) ({ \
int __ret_warn_on = !!(condition); \
if (unlikely(__ret_warn_on)) \
- printf(format); \
+ __WARN_printf(format); \
unlikely(__ret_warn_on); \
})
#endif
@@ -205,18 +216,17 @@ static LW_INLINE void *kmalloc (size_t size, int flags)
({ \
int __ret_warn_on = !!(x); \
if (unlikely(__ret_warn_on)) \
- printf("WARNING in %s line %d\n" \
- , __FILE__, __LINE__); \
+ __WARN_printf("WARNING in %s line %d\n", __FILE__, __LINE__); \
unlikely(__ret_warn_on); \
})
#endif
#ifndef WARN_ON_ONCE
#define WARN_ON_ONCE(condition) ({ \
- static bool __warned; \
+ static BOOL __warned; \
int __ret_warn_once = !!(condition); \
if (unlikely(__ret_warn_once && !__warned)) { \
- __warned = true; \
+ __warned = LW_TRUE; \
WARN_ON(1); \
} \
unlikely(__ret_warn_once); \
diff --git a/SylixOS/kernel/cache/cache.c b/SylixOS/kernel/cache/cache.c
index 99c03cc..dc52e30 100644
--- a/SylixOS/kernel/cache/cache.c
+++ b/SylixOS/kernel/cache/cache.c
@@ -752,14 +752,11 @@ INT API_CacheTextUpdate (PVOID pvAdrs, size_t stBytes)
INTREG iregInterLevel;
INT iError;
#if (LW_CFG_SMP_EN > 0) && (LW_CFG_VMM_L4_HYPERVISOR_EN == 0)
+ ULONG ulNesting;
LW_CACHE_TU_ARG tuarg;
BOOL bLock;
#endif /* LW_CFG_SMP_EN */
/* !LW_CFG_VMM_L4_HYPERVISOR_EN */
- if (LW_CPU_GET_CUR_NESTING()) { /* 不能在中断中调用 */
- _ErrorHandle(ERROR_KERNEL_IN_ISR);
- return (PX_ERROR);
- }
__CACHE_OP_ENTER(iregInterLevel); /* 开始操作 cache */
iError = ((_G_cacheopLib.CACHEOP_pfuncTextUpdate == LW_NULL) ? ERROR_NONE :
@@ -767,15 +764,21 @@ INT API_CacheTextUpdate (PVOID pvAdrs, size_t stBytes)
__CACHE_OP_EXIT(iregInterLevel); /* 结束操作 cache */
#if (LW_CFG_SMP_EN > 0) && (LW_CFG_VMM_L4_HYPERVISOR_EN == 0)
+ ulNesting = LW_CPU_GET_CUR_NESTING();
+
if ((_G_cacheopLib.CACHEOP_ulOption & CACHE_TEXT_UPDATE_MP) &&
(LW_NCPUS > 1)) { /* 需要通知其他 CPU */
tuarg.TUA_pvAddr = pvAdrs;
tuarg.TUA_stSize = stBytes;
- bLock = __SMP_CPU_LOCK(); /* 锁定当前 CPU 执行 */
+ if (!ulNesting) {
+ bLock = __SMP_CPU_LOCK(); /* 锁定当前 CPU 执行 */
+ }
_SmpCallFuncAllOther(__cacheTextUpdate, &tuarg,
LW_NULL, LW_NULL, IPIM_OPT_NORMAL); /* 通知其他的 CPU */
- __SMP_CPU_UNLOCK(bLock); /* 解锁当前 CPU 执行 */
+ if (!ulNesting) {
+ __SMP_CPU_UNLOCK(bLock); /* 解锁当前 CPU 执行 */
+ }
}
#endif /* LW_CFG_SMP_EN */
/* !LW_CFG_VMM_L4_HYPERVISOR_EN */
diff --git a/SylixOS/kernel/cdump/cdumpLib.c b/SylixOS/kernel/cdump/cdumpLib.c
index a372921..636d832 100644
--- a/SylixOS/kernel/cdump/cdumpLib.c
+++ b/SylixOS/kernel/cdump/cdumpLib.c
@@ -119,9 +119,9 @@ VOID _CrashDumpAbortKernel (LW_OBJECT_HANDLE ulOwner,
CPCHAR pcInfo,
CPCHAR pcTail)
{
- PLW_VMM_PAGE_FAIL_CTX pvmpagefailctx = (PLW_VMM_PAGE_FAIL_CTX)pvCtx;
- PCHAR pcCdump = (PCHAR)_K_pvCrashDumpBuffer;
- size_t stOft;
+ PLW_VMM_ABORT_CTX pabtctx = (PLW_VMM_ABORT_CTX)pvCtx;
+ PCHAR pcCdump = (PCHAR)_K_pvCrashDumpBuffer;
+ size_t stOft;
if (!pcCdump || (pcCdump == (PCHAR)PX_ERROR)) {
return;
@@ -135,7 +135,7 @@ VOID _CrashDumpAbortKernel (LW_OBJECT_HANDLE ulOwner,
pcCdump[3] = LW_CDUMP_MAGIC_3;
archTaskCtxPrint(&pcCdump[4], (LW_CDUMP_MAX_LEN - LW_CDUMP_MAGIC_LEN),
- &pvmpagefailctx->PAGEFCTX_archRegCtx);
+ &pabtctx->ABTCTX_archRegCtx);
stOft = lib_strlen(pcCdump);
@@ -144,8 +144,8 @@ VOID _CrashDumpAbortKernel (LW_OBJECT_HANDLE ulOwner,
"kowner: 0x%08lx, kfunc: %s, "
"ret_addr: 0x%08lx abt_addr: 0x%08lx, abt_type: %s, %s.\n",
ulOwner, pcKernelFunc,
- pvmpagefailctx->PAGEFCTX_ulRetAddr,
- pvmpagefailctx->PAGEFCTX_ulAbortAddr, pcInfo, pcTail);
+ pabtctx->ABTCTX_ulRetAddr,
+ pabtctx->ABTCTX_ulAbortAddr, pcInfo, pcTail);
}
/*********************************************************************************************************
** 函数名称: _CrashDumpAbortAccess
@@ -158,9 +158,9 @@ VOID _CrashDumpAbortKernel (LW_OBJECT_HANDLE ulOwner,
*********************************************************************************************************/
VOID _CrashDumpAbortAccess (PVOID pvCtx, CPCHAR pcInfo)
{
- PLW_VMM_PAGE_FAIL_CTX pvmpagefailctx = (PLW_VMM_PAGE_FAIL_CTX)pvCtx;
- PCHAR pcCdump = (PCHAR)_K_pvCrashDumpBuffer;
- size_t stOft;
+ PLW_VMM_ABORT_CTX pabtctx = (PLW_VMM_ABORT_CTX)pvCtx;
+ PCHAR pcCdump = (PCHAR)_K_pvCrashDumpBuffer;
+ size_t stOft;
if (!pcCdump || (pcCdump == (PCHAR)PX_ERROR)) {
return;
@@ -174,40 +174,40 @@ VOID _CrashDumpAbortAccess (PVOID pvCtx, CPCHAR pcInfo)
pcCdump[3] = LW_CDUMP_MAGIC_3;
archTaskCtxPrint(&pcCdump[4], (LW_CDUMP_MAX_LEN - LW_CDUMP_MAGIC_LEN),
- &pvmpagefailctx->PAGEFCTX_archRegCtx);
+ &pabtctx->ABTCTX_archRegCtx);
stOft = lib_strlen(pcCdump);
- switch (__PAGEFAILCTX_ABORT_TYPE(pvmpagefailctx)) {
+ switch (__ABTCTX_ABORT_TYPE(pabtctx)) {
case LW_VMM_ABORT_TYPE_UNDEF:
stOft = bnprintf(pcCdump, LW_CDUMP_MAX_LEN, stOft,
"UNDEF ERROR: abort in thread %lx[%s]. "
"ret_addr: 0x%08lx abt_addr: 0x%08lx, abt_type: %s.\n",
- pvmpagefailctx->PAGEFCTX_ptcb->TCB_ulId,
- pvmpagefailctx->PAGEFCTX_ptcb->TCB_cThreadName,
- pvmpagefailctx->PAGEFCTX_ulRetAddr,
- pvmpagefailctx->PAGEFCTX_ulAbortAddr, pcInfo);
+ pabtctx->ABTCTX_ptcb->TCB_ulId,
+ pabtctx->ABTCTX_ptcb->TCB_cThreadName,
+ pabtctx->ABTCTX_ulRetAddr,
+ pabtctx->ABTCTX_ulAbortAddr, pcInfo);
break;
case LW_VMM_ABORT_TYPE_FPE:
stOft = bnprintf(pcCdump, LW_CDUMP_MAX_LEN, stOft,
"FPU ERROR: abort in thread %lx[%s]. "
"ret_addr: 0x%08lx abt_addr: 0x%08lx, abt_type: %s.\n",
- pvmpagefailctx->PAGEFCTX_ptcb->TCB_ulId,
- pvmpagefailctx->PAGEFCTX_ptcb->TCB_cThreadName,
- pvmpagefailctx->PAGEFCTX_ulRetAddr,
- pvmpagefailctx->PAGEFCTX_ulAbortAddr, pcInfo);
+ pabtctx->ABTCTX_ptcb->TCB_ulId,
+ pabtctx->ABTCTX_ptcb->TCB_cThreadName,
+ pabtctx->ABTCTX_ulRetAddr,
+ pabtctx->ABTCTX_ulAbortAddr, pcInfo);
break;
default:
stOft = bnprintf(pcCdump, LW_CDUMP_MAX_LEN, stOft,
"ACCESS ERROR: abort in thread %lx[%s]. "
"ret_addr: 0x%08lx abt_addr: 0x%08lx, abt_type: %s.\n",
- pvmpagefailctx->PAGEFCTX_ptcb->TCB_ulId,
- pvmpagefailctx->PAGEFCTX_ptcb->TCB_cThreadName,
- pvmpagefailctx->PAGEFCTX_ulRetAddr,
- pvmpagefailctx->PAGEFCTX_ulAbortAddr, pcInfo);
+ pabtctx->ABTCTX_ptcb->TCB_ulId,
+ pabtctx->ABTCTX_ptcb->TCB_cThreadName,
+ pabtctx->ABTCTX_ulRetAddr,
+ pabtctx->ABTCTX_ulAbortAddr, pcInfo);
break;
}
diff --git a/SylixOS/kernel/include/k_kernel.h b/SylixOS/kernel/include/k_kernel.h
index b16a6f6..5d035a4 100644
--- a/SylixOS/kernel/include/k_kernel.h
+++ b/SylixOS/kernel/include/k_kernel.h
@@ -82,7 +82,7 @@
__SYLIXOS_PATCH_PAD)
#define __SYLIXOS_RELSTR "Tangram"
-#define __SYLIXOS_VERINFO "SylixOS kernel version: " \
+#define __SYLIXOS_VERINFO "AIC-OS kernel version: " \
__SYLIXOS_VERSTR \
" Code name: " __SYLIXOS_RELSTR
#define __SYLIXOS_LICENSE "SylixOS license: Commercial & GPL."
diff --git a/SylixOS/kernel/include/k_logo.h b/SylixOS/kernel/include/k_logo.h
index 112d601..6610a6f 100644
--- a/SylixOS/kernel/include/k_logo.h
+++ b/SylixOS/kernel/include/k_logo.h
@@ -25,22 +25,24 @@
/*********************************************************************************************************
系统 LOGO
*********************************************************************************************************/
+#define __SYLIXOS_LOGO "\n [[ [[[[[[ [[[[ [[[[ [[[[ (R)" \
+ "\n [[[[ [[ [[ [[ [[ [[ [[ [[" \
+ "\n[[ [[ [[ [[ [[ [[ [[ [[ " \
+ "\n[[ [[ [[ [[ [[ [[ [[ " \
+ "\n[[ [[ [[ [[ [[[[[[ [[ [[ [[ " \
+ "\n[[ [[ [[ [[ [[ [[ [[ " \
+ "\n[[[[[[ [[ [[ [[ [[ [[" \
+ "\n[[ [[ [[ [[ [[ [[ [[ [[" \
+ "\n[[ [[ [[ [[ [[ [[ [[ [[ [[" \
+ "\n[[ [[ [[[[[[ [[[[ [[[[ [[[[ " \
+ "\n" \
+ "\n COPYRIGHT SAST 804 Inst. & ACOINFO 2006 - 2019\n\n" \
+ "\n KERNEL: Long-Wing(C) " __SYLIXOS_VERSTR "" \
+ " Based on SylixOS(R) 2006-2019 \n\n"
-#define __SYLIXOS_LOGO "\n [[ (R)" \
- "\n [[[[ [[[[ [[ [[[[ [[[[ " \
- "\n[[ [[ [[ [[ [[ [[ [[" \
- "\n[[ [[ [[ [[ [[[[ [[ [[ [[ [[ [[ " \
- "\n [[ [[ [[ [[ [[ [[ [[ [[ [[ [[ " \
- "\n [[ [[ [[ [[ [[ [[[[ [[ [[ [[ " \
- "\n [[ [[ [[ [[ [[ [[ [[ [[ [[ " \
- "\n [[ [[ [[ [[ [[ [[[[ [[ [[ [[" \
- "\n[[ [[ [[ [[ [[ [[ [[ [[ [[ [[ [[ [[" \
- "\n [[[[ [[[[ [[[[[[ [[[[[[ [[ [[ [[[[ [[[[ " \
- "\n [[ " \
- "\n [[ KERNEL: LongWing(C) " __SYLIXOS_VERSTR "" \
- "\n [[[[ COPYRIGHT ACOINFO Co. Ltd. 2006 - 2019\n\n"
#endif /* __K_LOGO_H */
+
/*********************************************************************************************************
END
*********************************************************************************************************/
diff --git a/SylixOS/kernel/show/BacktraceShow.c b/SylixOS/kernel/show/BacktraceShow.c
index c77fc5e..dd66dd8 100644
--- a/SylixOS/kernel/show/BacktraceShow.c
+++ b/SylixOS/kernel/show/BacktraceShow.c
@@ -30,6 +30,7 @@
*********************************************************************************************************/
#if LW_CFG_MODULELOADER_EN > 0
#include "dlfcn.h"
+#include "../SylixOS/loader/include/loader_lib.h"
#include "../SylixOS/loader/include/loader_vppatch.h"
#endif /* LW_CFG_MODULELOADER_EN > 0 */
/*********************************************************************************************************
@@ -73,15 +74,31 @@ VOID API_BacktraceShow (INT iFd, INT iMaxDepth)
for (i = 0; i < iCnt; i++) {
if ((API_ModuleAddr(pvFrame[i], &dlinfo, pvproc) == ERROR_NONE) &&
(dlinfo.dli_sname)) {
+ PVOID pvBaseAddr;
+
+ pvBaseAddr = dlinfo.dli_fbase ? \
+ ((LW_LD_EXEC_MODULE *)dlinfo.dli_fbase)->EMOD_pvBaseAddr : LW_NULL;
if (iFd >= 0) {
- fdprintf(iFd, "[%02d] %p (%s+%zu)\n", iCnt - i, pvFrame[i], dlinfo.dli_sname,
- ((size_t)pvFrame[i] - (size_t)dlinfo.dli_saddr));
+ fdprintf(iFd, "[%02d] %p (%s@%p+0x%x %s+%zu)\n",
+ iCnt - i,
+ pvFrame[i],
+ dlinfo.dli_fname,
+ pvBaseAddr,
+ pvFrame[i] - pvBaseAddr,
+ dlinfo.dli_sname,
+ ((size_t)pvFrame[i] - (size_t)dlinfo.dli_saddr));
+
} else {
- _DebugFormat(__PRINTMESSAGE_LEVEL, "[%02d] %p (%s+%zu)\r\n",
- iCnt - i, pvFrame[i], dlinfo.dli_sname,
- ((size_t)pvFrame[i] - (size_t)dlinfo.dli_saddr));
+ _DebugFormat(__PRINTMESSAGE_LEVEL, "[%02d] %p (%s@%p+0x%x %s+%zu)\r\n",
+ iCnt - i,
+ pvFrame[i],
+ dlinfo.dli_fname,
+ pvBaseAddr,
+ pvFrame[i] - pvBaseAddr,
+ dlinfo.dli_sname,
+ ((size_t)pvFrame[i] - (size_t)dlinfo.dli_saddr));
}
-
+
} else {
if (iFd >= 0) {
fdprintf(iFd, "[%02d] %p (<unknown>)\n", iCnt - i, pvFrame[i]);
@@ -143,10 +160,20 @@ VOID API_BacktracePrint (PVOID pvBuffer, size_t stSize, INT iMaxDepth)
for (i = 0; i < iCnt; i++) {
if ((API_ModuleAddr(pvFrame[i], &dlinfo, pvproc) == ERROR_NONE) &&
(dlinfo.dli_sname)) {
- stOft = bnprintf(pvBuffer, stSize, stOft, "[%02d] %p (%s+%zu)\n",
- iCnt - i, pvFrame[i], dlinfo.dli_sname,
- ((size_t)pvFrame[i] - (size_t)dlinfo.dli_saddr));
-
+ PVOID pvBaseAddr;
+
+ pvBaseAddr = dlinfo.dli_fbase ? \
+ ((LW_LD_EXEC_MODULE *)dlinfo.dli_fbase)->EMOD_pvBaseAddr : LW_NULL;
+
+ stOft = bnprintf(pvBuffer, stSize, stOft, "[%02d] %p (%s@%p+0x%x %s+%zu)\n",
+ iCnt - i,
+ pvFrame[i],
+ dlinfo.dli_fname,
+ pvBaseAddr,
+ pvFrame[i] - pvBaseAddr,
+ dlinfo.dli_sname,
+ ((size_t)pvFrame[i] - (size_t)dlinfo.dli_saddr));
+
} else {
stOft = bnprintf(pvBuffer, stSize, stOft, "[%02d] %p (<unknown>)\n", iCnt - i, pvFrame[i]);
}
diff --git a/SylixOS/kernel/vmm/vmm.h b/SylixOS/kernel/vmm/vmm.h
index 2de94c3..e2d02e3 100644
--- a/SylixOS/kernel/vmm/vmm.h
+++ b/SylixOS/kernel/vmm/vmm.h
@@ -351,7 +351,31 @@ typedef LW_VMM_ABORT *PLW_VMM_ABORT;
LW_API VOID API_VmmAbortIsr(addr_t ulRetAddr,
addr_t ulAbortAddr,
PLW_VMM_ABORT pabtInfo,
- PLW_CLASS_TCB ptcb); /* 异常中断服务函数 */
+ PLW_CLASS_TCB ptcb); /* 异常服务函数 */
+
+LW_API VOID API_VmmAbortIsrEx(addr_t ulRetAddr,
+ addr_t ulAbortAddr,
+ PLW_VMM_ABORT pabtInfo,
+ PLW_CLASS_TCB ptcb,
+ VOIDFUNCPTR pfuncHandler); /* 自定义异常服务函数 */
+
+/*********************************************************************************************************
+ 异常返回
+*********************************************************************************************************/
+
+typedef struct {
+ ARCH_REG_CTX ABTCTX_archRegCtx; /* 寄存器上下文 */
+ addr_t ABTCTX_ulRetAddr; /* 异常返回地址 */
+ addr_t ABTCTX_ulAbortAddr; /* 异常地址 */
+ LW_VMM_ABORT ABTCTX_abtInfo; /* 异常类型 */
+ PLW_CLASS_TCB ABTCTX_ptcb; /* 产生异常的线程 */
+
+ errno_t ABTCTX_iLastErrno; /* 返回时需要恢复的信息 */
+ INT ABTCTX_iKernelSpace;
+} LW_VMM_ABORT_CTX;
+typedef LW_VMM_ABORT_CTX *PLW_VMM_ABORT_CTX;
+
+LW_API VOID API_VmmAbortReturn(PLW_VMM_ABORT_CTX pabtctx);
#endif /* __SYLIXOS_KERNEL */
/*********************************************************************************************************
diff --git a/SylixOS/kernel/vmm/vmmAbort.c b/SylixOS/kernel/vmm/vmmAbort.c
index aba7d93..4b81b3b 100644
--- a/SylixOS/kernel/vmm/vmmAbort.c
+++ b/SylixOS/kernel/vmm/vmmAbort.c
@@ -84,8 +84,8 @@ static LW_VMM_STATUS _K_vmmStatus;
/*********************************************************************************************************
内部函数声明
*********************************************************************************************************/
-static VOID __vmmAbortKill(PLW_VMM_PAGE_FAIL_CTX pvmpagefailctx);
-static VOID __vmmAbortAccess(PLW_VMM_PAGE_FAIL_CTX pvmpagefailctx);
+static VOID __vmmAbortKill(PLW_VMM_ABORT_CTX pabtctx);
+static VOID __vmmAbortAccess(PLW_VMM_ABORT_CTX pabtctx);
static PCHAR __vmmAbortTypeStr(PLW_VMM_ABORT pabtInfo);
/*********************************************************************************************************
基本参数
@@ -526,14 +526,14 @@ static INT __vmmAbortShare (PLW_VMM_PAGE pvmpageVirtual,
/*********************************************************************************************************
** 函数名称: __vmmAbortDump
** 功能描述: 当 __vmmAbortShell() 无法执行时, 打印调试信息
-** 输 入 : pvmpagefailctx page fail 上下文
+** 输 入 : pabtctx page fail 上下文
** 输 出 : NONE
** 全局变量:
** 调用模块:
*********************************************************************************************************/
-static VOID __vmmAbortDump (PLW_VMM_PAGE_FAIL_CTX pvmpagefailctx)
+static VOID __vmmAbortDump (PLW_VMM_ABORT_CTX pabtctx)
{
- addr_t ulAbortAddr = pvmpagefailctx->PAGEFCTX_ulAbortAddr;
+ addr_t ulAbortAddr = pabtctx->ABTCTX_ulAbortAddr;
LW_OBJECT_HANDLE ulOwner;
PCHAR pcTail;
CPCHAR pcKernelFunc;
@@ -564,8 +564,8 @@ static VOID __vmmAbortDump (PLW_VMM_PAGE_FAIL_CTX pvmpagefailctx)
}
#if (LW_CFG_CDUMP_EN > 0) && (LW_CFG_DEVICE_EN > 0)
- _CrashDumpAbortKernel(ulOwner, pcKernelFunc, pvmpagefailctx,
- __vmmAbortTypeStr(&pvmpagefailctx->PAGEFCTX_abtInfo),
+ _CrashDumpAbortKernel(ulOwner, pcKernelFunc, pabtctx,
+ __vmmAbortTypeStr(&pabtctx->ABTCTX_abtInfo),
pcTail);
#endif
@@ -574,23 +574,23 @@ static VOID __vmmAbortDump (PLW_VMM_PAGE_FAIL_CTX pvmpagefailctx)
"kowner: 0x%08lx, kfunc: %s, "
"ret_addr: 0x%08lx abt_addr: 0x%08lx, abt_type: %s, %s.\r\n",
ulOwner, pcKernelFunc,
- pvmpagefailctx->PAGEFCTX_ulRetAddr,
- pvmpagefailctx->PAGEFCTX_ulAbortAddr,
- __vmmAbortTypeStr(&pvmpagefailctx->PAGEFCTX_abtInfo),
+ pabtctx->ABTCTX_ulRetAddr,
+ pabtctx->ABTCTX_ulAbortAddr,
+ __vmmAbortTypeStr(&pabtctx->ABTCTX_abtInfo),
pcTail);
}
/*********************************************************************************************************
** 函数名称: __vmmAbortShell
** 功能描述: 当 MMU 产生访问失效时, 线程执行陷阱函数.
-** 输 入 : pvmpagefailctx page fail 上下文
+** 输 入 : pabtctx page fail 上下文
** 输 出 : NONE
** 全局变量:
** 调用模块:
*********************************************************************************************************/
-static VOID __vmmAbortShell (PLW_VMM_PAGE_FAIL_CTX pvmpagefailctx)
+static VOID __vmmAbortShell (PLW_VMM_ABORT_CTX pabtctx)
{
INTREG iregInterLevel;
- addr_t ulAbortAddr = pvmpagefailctx->PAGEFCTX_ulAbortAddr;
+ addr_t ulAbortAddr = pabtctx->ABTCTX_ulAbortAddr;
ULONG ulFlag;
REGISTER PLW_VMM_PAGE pvmpageVirtual;
@@ -606,8 +606,8 @@ static VOID __vmmAbortShell (PLW_VMM_PAGE_FAIL_CTX pvmpagefailctx)
PLW_CLASS_TCB ptcbCur; /* 当前任务控制块 */
if (__KERNEL_ISENTER()) {
- __vmmAbortDump(pvmpagefailctx); /* 打印关键信息 */
- __vmmAbortKill(pvmpagefailctx);
+ __vmmAbortDump(pabtctx); /* 打印关键信息 */
+ __vmmAbortKill(pabtctx);
goto __abort_return;
}
@@ -616,10 +616,10 @@ static VOID __vmmAbortShell (PLW_VMM_PAGE_FAIL_CTX pvmpagefailctx)
__VMM_LOCK();
_K_vmmStatus.VMMS_i64AbortCounter++;
- if ((__PAGEFAILCTX_ABORT_TYPE(pvmpagefailctx) != LW_VMM_ABORT_TYPE_MAP) &&
- (__PAGEFAILCTX_ABORT_TYPE(pvmpagefailctx) != LW_VMM_ABORT_TYPE_PERM)) {
+ if ((__ABTCTX_ABORT_TYPE(pabtctx) != LW_VMM_ABORT_TYPE_MAP) &&
+ (__ABTCTX_ABORT_TYPE(pabtctx) != LW_VMM_ABORT_TYPE_PERM)) {
__VMM_UNLOCK();
- __vmmAbortAccess(pvmpagefailctx); /* 访问异常情况 */
+ __vmmAbortAccess(pabtctx); /* 访问异常情况 */
goto __abort_return; /* 不会运行到这里 */
}
@@ -628,7 +628,7 @@ static VOID __vmmAbortShell (PLW_VMM_PAGE_FAIL_CTX pvmpagefailctx)
pvmpagep = (PLW_VMM_PAGE_PRIVATE)pvmpageVirtual->PAGE_pvAreaCb;
} else {
__VMM_UNLOCK();
- __vmmAbortAccess(pvmpagefailctx); /* 访问异常 */
+ __vmmAbortAccess(pabtctx); /* 访问异常 */
goto __abort_return; /* 不会运行到这里 */
}
@@ -639,14 +639,12 @@ static VOID __vmmAbortShell (PLW_VMM_PAGE_FAIL_CTX pvmpagefailctx)
ulError = __vmmLibGetFlag(ulVirtualPageAlign, &ulFlag); /* 获得异常地址的物理页面属性 */
if (ulError == ERROR_NONE) { /* 存在物理页面正常 */
- if (__PAGEFAILCTX_ABORT_TYPE(pvmpagefailctx) ==
- LW_VMM_ABORT_TYPE_MAP) { /* MAP 类型错误 */
+ if (__ABTCTX_ABORT_TYPE(pabtctx) == LW_VMM_ABORT_TYPE_MAP) { /* MAP 类型错误 */
__VMM_UNLOCK();
goto __abort_return; /* 页表已经正常, 可以访问 */
}
-
- if (__PAGEFAILCTX_ABORT_METHOD(pvmpagefailctx) ==
- LW_VMM_ABORT_METHOD_WRITE) { /* 写入异常 */
+ /* 写入异常 */
+ if (__ABTCTX_ABORT_METHOD(pabtctx) == LW_VMM_ABORT_METHOD_WRITE) {
if (__vmmAbortWriteProtect(pvmpageVirtual, /* 尝试 copy-on-write 处理 */
ulAbortAddr,
ulFlag, ptcbCur) == ERROR_NONE) {/* 进入写保护处理 */
@@ -656,7 +654,7 @@ static VOID __vmmAbortShell (PLW_VMM_PAGE_FAIL_CTX pvmpagefailctx)
}
__VMM_UNLOCK();
- __vmmAbortAccess(pvmpagefailctx); /* 非法内存访问 */
+ __vmmAbortAccess(pabtctx); /* 非法内存访问 */
goto __abort_return; /* 不会运行到这里 */
} else { /* 映射错误, 没有物理页面存在 */
@@ -675,10 +673,9 @@ static VOID __vmmAbortShell (PLW_VMM_PAGE_FAIL_CTX pvmpagefailctx)
if (pvmpagePhysical == LW_NULL) {
__VMM_UNLOCK();
- __PAGEFAILCTX_ABORT_TYPE(pvmpagefailctx) =
- LW_VMM_ABORT_TYPE_NOINFO; /* 缺少物理页面 */
+ __ABTCTX_ABORT_TYPE(pabtctx) = LW_VMM_ABORT_TYPE_NOINFO; /* 缺少物理页面 */
printk(KERN_CRIT "kernel no more physical page.\n"); /* 系统无法分配物理页面 */
- __vmmAbortKill(pvmpagefailctx);
+ __vmmAbortKill(pabtctx);
goto __abort_return;
}
@@ -699,7 +696,7 @@ static VOID __vmmAbortShell (PLW_VMM_PAGE_FAIL_CTX pvmpagefailctx)
if (iRet != ERROR_NONE) {
__vmmPhysicalPageFree(pvmpagePhysical);
__VMM_UNLOCK();
- __vmmAbortKill(pvmpagefailctx);
+ __vmmAbortKill(pabtctx);
goto __abort_return;
}
}
@@ -714,7 +711,7 @@ static VOID __vmmAbortShell (PLW_VMM_PAGE_FAIL_CTX pvmpagefailctx)
__VMM_UNLOCK();
printk(KERN_CRIT "kernel physical page map error.\n"); /* 系统无法映射物理页面 */
- __vmmAbortKill(pvmpagefailctx);
+ __vmmAbortKill(pabtctx);
goto __abort_return;
}
@@ -725,12 +722,12 @@ static VOID __vmmAbortShell (PLW_VMM_PAGE_FAIL_CTX pvmpagefailctx)
__VMM_UNLOCK();
__abort_return:
- __KERNEL_SPACE_SET(pvmpagefailctx->PAGEFCTX_iKernelSpace); /* 恢复成进入之前的状态 */
- errno = pvmpagefailctx->PAGEFCTX_iLastErrno; /* 恢复之前的 errno */
+ __KERNEL_SPACE_SET(pabtctx->ABTCTX_iKernelSpace); /* 恢复成进入之前的状态 */
+ errno = pabtctx->ABTCTX_iLastErrno; /* 恢复之前的 errno */
iregInterLevel = KN_INT_DISABLE(); /* 关闭当前 CPU 中断 */
KN_SMP_MB();
- archSigCtxLoad(&pvmpagefailctx->PAGEFCTX_archRegCtx); /* 从 page fail 上下文中返回 */
+ archSigCtxLoad(&pabtctx->ABTCTX_archRegCtx); /* 从 page fail 上下文中返回 */
KN_INT_ENABLE(iregInterLevel); /* 运行不到这里 */
}
@@ -800,12 +797,12 @@ static PCHAR __vmmAbortTypeStr (PLW_VMM_ABORT pabtInfo)
/*********************************************************************************************************
** 函数名称: __vmmAbortKill
** 功能描述: 向当前线程产生一个信号
-** 输 入 : pvmpagefailctx page fail 上下文
+** 输 入 : pabtctx page fail 上下文
** 输 出 : NONE
** 全局变量:
** 调用模块:
*********************************************************************************************************/
-static VOID __vmmAbortKill (PLW_VMM_PAGE_FAIL_CTX pvmpagefailctx)
+static VOID __vmmAbortKill (PLW_VMM_ABORT_CTX pabtctx)
{
#if LW_CFG_SIGNAL_EN > 0
struct sigevent sigeventAbort;
@@ -815,14 +812,14 @@ static VOID __vmmAbortKill (PLW_VMM_PAGE_FAIL_CTX pvmpagefailctx)
#if LW_CFG_GDB_EN > 0
if (!__KERNEL_ISENTER()) {
- if (API_DtraceAbortTrap(pvmpagefailctx->PAGEFCTX_ulRetAddr) ==
+ if (API_DtraceAbortTrap(pabtctx->ABTCTX_ulRetAddr) ==
ERROR_NONE) { /* 可以通知调试器 */
return; /* 返回后将会产生断点 */
}
}
#endif /* LW_CFG_GDB_EN > 0 */
- _BugHandle((_ObjectGetIndex(pvmpagefailctx->PAGEFCTX_ptcb->TCB_ulId) < LW_NCPUS),
+ _BugHandle((_ObjectGetIndex(pabtctx->ABTCTX_ptcb->TCB_ulId) < LW_NCPUS),
LW_TRUE, "idle thread serious error!\r\n");
#if LW_CFG_SIGNAL_EN > 0
@@ -830,7 +827,7 @@ static VOID __vmmAbortKill (PLW_VMM_PAGE_FAIL_CTX pvmpagefailctx)
API_KernelReboot(LW_REBOOT_FORCE); /* 直接重新启动操作系统 */
}
- switch (__PAGEFAILCTX_ABORT_TYPE(pvmpagefailctx)) { /* 分析异常类型 */
+ switch (__ABTCTX_ABORT_TYPE(pabtctx)) { /* 分析异常类型 */
case 0:
sigeventAbort.sigev_signo = SIGKILL; /* 通过 SIGKILL 信号杀死任务 */
@@ -840,13 +837,13 @@ static VOID __vmmAbortKill (PLW_VMM_PAGE_FAIL_CTX pvmpagefailctx)
case LW_VMM_ABORT_TYPE_FPE:
sigeventAbort.sigev_signo = SIGFPE;
- iSigCode = __PAGEFAILCTX_ABORT_METHOD(pvmpagefailctx);
+ iSigCode = __ABTCTX_ABORT_METHOD(pabtctx);
bSerious = LW_TRUE;
break;
case LW_VMM_ABORT_TYPE_BUS:
sigeventAbort.sigev_signo = SIGBUS;
- iSigCode = __PAGEFAILCTX_ABORT_METHOD(pvmpagefailctx);
+ iSigCode = __ABTCTX_ABORT_METHOD(pabtctx);
bSerious = LW_TRUE;
break;
@@ -876,13 +873,13 @@ static VOID __vmmAbortKill (PLW_VMM_PAGE_FAIL_CTX pvmpagefailctx)
break;
}
- sigeventAbort.sigev_value.sival_ptr = (PVOID)pvmpagefailctx->PAGEFCTX_ulAbortAddr;
+ sigeventAbort.sigev_value.sival_ptr = (PVOID)pabtctx->ABTCTX_ulAbortAddr;
sigeventAbort.sigev_notify = SIGEV_SIGNAL;
- _doSigEvent(pvmpagefailctx->PAGEFCTX_ptcb->TCB_ulId, &sigeventAbort, iSigCode);
+ _doSigEvent(pabtctx->ABTCTX_ptcb->TCB_ulId, &sigeventAbort, iSigCode);
if (LW_KERN_BUG_REBOOT_EN_GET()) {
- if (bSerious && !vprocGetPidByTcbNoLock(pvmpagefailctx->PAGEFCTX_ptcb)) {
+ if (bSerious && !vprocGetPidByTcbNoLock(pabtctx->ABTCTX_ptcb)) {
API_KernelReboot(LW_REBOOT_FORCE); /* 内核线程严重错误 */
}
}
@@ -898,18 +895,17 @@ static VOID __vmmAbortKill (PLW_VMM_PAGE_FAIL_CTX pvmpagefailctx)
/*********************************************************************************************************
** 函数名称: __vmmAbortAccess
** 功能描述: 访问型错误处理 (此函数不会返回)
-** 输 入 : pvmpagefailctx page fail 上下文
+** 输 入 : pabtctx page fail 上下文
** 输 出 : NONE
** 全局变量:
** 调用模块:
*********************************************************************************************************/
-static VOID __vmmAbortAccess (PLW_VMM_PAGE_FAIL_CTX pvmpagefailctx)
+static VOID __vmmAbortAccess (PLW_VMM_ABORT_CTX pabtctx)
{
INTREG iregInterLevel;
- ULONG ulErrorOrig = API_GetLastError();
#if (LW_CFG_CDUMP_EN > 0) && (LW_CFG_DEVICE_EN > 0)
- _CrashDumpAbortAccess(pvmpagefailctx, __vmmAbortTypeStr(&pvmpagefailctx->PAGEFCTX_abtInfo));
+ _CrashDumpAbortAccess(pabtctx, __vmmAbortTypeStr(&pabtctx->ABTCTX_abtInfo));
#endif
#if LW_CFG_ABORT_CALLSTACK_INFO_EN > 0
@@ -917,20 +913,20 @@ static VOID __vmmAbortAccess (PLW_VMM_PAGE_FAIL_CTX pvmpagefailctx)
#endif /* LW_CFG_ABORT_CALLSTACK_IN...*/
#if LW_CFG_DEVICE_EN > 0
- archTaskCtxShow(ioGlobalStdGet(STD_ERR), &pvmpagefailctx->PAGEFCTX_archRegCtx);
+ archTaskCtxShow(ioGlobalStdGet(STD_ERR), &pabtctx->ABTCTX_archRegCtx);
#endif
#if LW_CFG_ABORT_BASIC_INFO_EN > 0
- switch (__PAGEFAILCTX_ABORT_TYPE(pvmpagefailctx)) {
+ switch (__ABTCTX_ABORT_TYPE(pabtctx)) {
case LW_VMM_ABORT_TYPE_UNDEF:
printk(KERN_EMERG "UNDEF ERROR: abort in thread %lx[%s]. \n"
"ret_addr: 0x%08lx abt_addr: 0x%08lx, abt_type: %s.\n",
- pvmpagefailctx->PAGEFCTX_ptcb->TCB_ulId,
- pvmpagefailctx->PAGEFCTX_ptcb->TCB_cThreadName,
- pvmpagefailctx->PAGEFCTX_ulRetAddr,
- pvmpagefailctx->PAGEFCTX_ulAbortAddr,
- __vmmAbortTypeStr(&pvmpagefailctx->PAGEFCTX_abtInfo)); /* 操作异常 */
+ pabtctx->ABTCTX_ptcb->TCB_ulId,
+ pabtctx->ABTCTX_ptcb->TCB_cThreadName,
+ pabtctx->ABTCTX_ulRetAddr,
+ pabtctx->ABTCTX_ulAbortAddr,
+ __vmmAbortTypeStr(&pabtctx->ABTCTX_abtInfo)); /* 操作异常 */
break;
case LW_VMM_ABORT_TYPE_FPE:
@@ -945,11 +941,11 @@ static VOID __vmmAbortAccess (PLW_VMM_PAGE_FAIL_CTX pvmpagefailctx)
#endif /* LW_CFG_CPU_FPU_EN > 0 */
printk(KERN_EMERG "FPU ERROR: abort in thread %lx[%s]. "
"ret_addr: 0x%08lx abt_addr: 0x%08lx, abt_type: %s.\n",
- pvmpagefailctx->PAGEFCTX_ptcb->TCB_ulId,
- pvmpagefailctx->PAGEFCTX_ptcb->TCB_cThreadName,
- pvmpagefailctx->PAGEFCTX_ulRetAddr,
- pvmpagefailctx->PAGEFCTX_ulAbortAddr,
- __vmmAbortTypeStr(&pvmpagefailctx->PAGEFCTX_abtInfo)); /* 操作异常 */
+ pabtctx->ABTCTX_ptcb->TCB_ulId,
+ pabtctx->ABTCTX_ptcb->TCB_cThreadName,
+ pabtctx->ABTCTX_ulRetAddr,
+ pabtctx->ABTCTX_ulAbortAddr,
+ __vmmAbortTypeStr(&pabtctx->ABTCTX_abtInfo)); /* 操作异常 */
break;
case LW_VMM_ABORT_TYPE_DSPE:
@@ -964,11 +960,11 @@ static VOID __vmmAbortAccess (PLW_VMM_PAGE_FAIL_CTX pvmpagefailctx)
#endif /* LW_CFG_CPU_DSP_EN > 0 */
printk(KERN_EMERG "DSP ERROR: abort in thread %lx[%s]. "
"ret_addr: 0x%08lx abt_addr: 0x%08lx, abt_type: %s.\n",
- pvmpagefailctx->PAGEFCTX_ptcb->TCB_ulId,
- pvmpagefailctx->PAGEFCTX_ptcb->TCB_cThreadName,
- pvmpagefailctx->PAGEFCTX_ulRetAddr,
- pvmpagefailctx->PAGEFCTX_ulAbortAddr,
- __vmmAbortTypeStr(&pvmpagefailctx->PAGEFCTX_abtInfo)); /* 操作异常 */
+ pabtctx->ABTCTX_ptcb->TCB_ulId,
+ pabtctx->ABTCTX_ptcb->TCB_cThreadName,
+ pabtctx->ABTCTX_ulRetAddr,
+ pabtctx->ABTCTX_ulAbortAddr,
+ __vmmAbortTypeStr(&pabtctx->ABTCTX_abtInfo)); /* 操作异常 */
break;
default:
@@ -988,16 +984,17 @@ static VOID __vmmAbortAccess (PLW_VMM_PAGE_FAIL_CTX pvmpagefailctx)
}
#endif /* LW_CFG_ABORT_BASIC_INFO_EN */
- __vmmAbortKill(pvmpagefailctx); /* 发送异常信号 */
+ __vmmAbortKill(pabtctx); /* 发送异常信号 */
- _ErrorHandle(ulErrorOrig); /* 恢复之前的 errno */
+ __KERNEL_SPACE_SET(pabtctx->ABTCTX_iKernelSpace); /* 恢复成进入之前的状态 */
+ errno = pabtctx->ABTCTX_iLastErrno; /* 恢复之前的 errno */
/*
* iRet == 0 or iRet > 0 都需要返回重新执行指令.
*/
iregInterLevel = KN_INT_DISABLE(); /* 关闭当前 CPU 中断 */
KN_SMP_MB();
- archSigCtxLoad(&pvmpagefailctx->PAGEFCTX_archRegCtx); /* 从 page fail 上下文中返回 */
+ archSigCtxLoad(&pabtctx->ABTCTX_archRegCtx); /* 从 page fail 上下文中返回 */
KN_INT_ENABLE(iregInterLevel); /* 运行不到这里 */
}
/*********************************************************************************************************
@@ -1120,32 +1117,52 @@ static VOID __vmmAbortStkOfDetected (addr_t ulRetAddr,
#endif /* LW_CFG_VMM_EN > 0 */
/*********************************************************************************************************
-** 函数名称: API_VmmAbortIsr
+** 函数名称: API_VmmAbortReturn
+** 功能描述: API_VmmAbortIsrEx 参数 pfuncHandler 返回时调用
+** 输 入 : pabtctx page fail 上下文
+** 输 出 : NONE
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+LW_API
+VOID API_VmmAbortReturn (PLW_VMM_ABORT_CTX pabtctx)
+{
+ INTREG iregInterLevel;
+
+ if (pabtctx->ABTCTX_abtInfo.VMABT_uiType) { /* 存在无法处理的异常 */
+ __vmmAbortAccess(pabtctx);
+ }
+
+ __KERNEL_SPACE_SET(pabtctx->ABTCTX_iKernelSpace); /* 恢复成进入之前的状态 */
+ errno = pabtctx->ABTCTX_iLastErrno; /* 恢复之前的 errno */
+
+ iregInterLevel = KN_INT_DISABLE(); /* 关闭当前 CPU 中断 */
+ KN_SMP_MB();
+ archSigCtxLoad(&pabtctx->ABTCTX_archRegCtx); /* 从 page fail 上下文中返回 */
+ KN_INT_ENABLE(iregInterLevel); /* 运行不到这里 */
+}
+/*********************************************************************************************************
+** 函数名称: API_VmmAbortIsrEx
** 功能描述: 当 MMU 产生访问失效时, 调用此函数(类似于中断服务函数)
** 输 入 : ulRetAddr 异常返回地址
** ulAbortAddr 异常地址 (异常类型相关)
** pabtInfo 异常类型
** ptcb 出现异常的线程控制块 (不能为 NULL)
+** pfuncHandler 异常处理函数
** 输 出 : NONE
** 全局变量:
** 调用模块:
-** 注 意 : 从 1.0.0.rc20 版本后, 此函数可以脱离 VMM 运行.
-**
-** 1. 构造缺页中断线程执行陷阱, 在陷阱中完成所有的页面操作, 如果失败, 线程自我销毁.
-** 2. 注意, 陷阱执行完毕后, 系统必须能够回到刚刚访问内存并产生异常的那条指令.
-** 3. 由于产生缺页中断时, 相关线程一定是就绪的, 所以这里不用加入调度器处理.
-
- API 函数
*********************************************************************************************************/
LW_API
-VOID API_VmmAbortIsr (addr_t ulRetAddr,
- addr_t ulAbortAddr,
- PLW_VMM_ABORT pabtInfo,
- PLW_CLASS_TCB ptcb)
+VOID API_VmmAbortIsrEx (addr_t ulRetAddr,
+ addr_t ulAbortAddr,
+ PLW_VMM_ABORT pabtInfo,
+ PLW_CLASS_TCB ptcb,
+ VOIDFUNCPTR pfuncHandler)
{
- PLW_VMM_PAGE_FAIL_CTX pvmpagefailctx;
- PLW_STACK pstkFailShell; /* 启动 fail shell 的堆栈点 */
- BYTE *pucStkNow; /* 记录还原堆栈点 */
+ PLW_VMM_ABORT_CTX pabtctx;
+ PLW_STACK pstkFailShell; /* 启动 fail shell 的堆栈点 */
+ BYTE *pucStkNow; /* 记录还原堆栈点 */
__vmmAbortFatalDetected(ulRetAddr, ulAbortAddr, pabtInfo, ptcb); /* 致命错误探测 */
@@ -1157,26 +1174,25 @@ VOID API_VmmAbortIsr (addr_t ulRetAddr,
/* 产生异常 */
pucStkNow = (BYTE *)archCtxStackEnd(&ptcb->TCB_archRegCtx); /* 记录还原堆栈点 */
#if CPU_STK_GROWTH == 0
- pucStkNow += sizeof(LW_STACK); /* 向空栈方向移动一个堆栈空间 */
- pucStkNow = (BYTE *)ROUND_UP(pucStkNow, ARCH_STK_ALIGN_SIZE);
- pvmpagefailctx = (PLW_VMM_PAGE_FAIL_CTX)pucStkNow; /* 记录 PAGE_FAIL_CTX 位置 */
- pucStkNow += __PAGEFAILCTX_SIZE_ALIGN; /* 让出 PAGE_FAIL_CTX 空间 */
+ pucStkNow += sizeof(LW_STACK); /* 向空栈方向移动一个堆栈空间 */
+ pucStkNow = (BYTE *)ROUND_UP(pucStkNow, ARCH_STK_ALIGN_SIZE);
+ pabtctx = (PLW_VMM_ABORT_CTX)pucStkNow; /* 记录 PAGE_FAIL_CTX 位置 */
+ pucStkNow += __ABTCTX_SIZE_ALIGN; /* 让出 PAGE_FAIL_CTX 空间 */
#else
- pucStkNow -= __PAGEFAILCTX_SIZE_ALIGN; /* 让出 PAGE_FAIL_CTX 空间 */
- pucStkNow = (BYTE *)ROUND_DOWN(pucStkNow, ARCH_STK_ALIGN_SIZE);
- pvmpagefailctx = (PLW_VMM_PAGE_FAIL_CTX)pucStkNow; /* 记录 PAGE_FAIL_CTX 位置 */
- pucStkNow -= sizeof(LW_STACK); /* 向空栈方向移动一个堆栈空间 */
+ pucStkNow -= __ABTCTX_SIZE_ALIGN; /* 让出 PAGE_FAIL_CTX 空间 */
+ pucStkNow = (BYTE *)ROUND_DOWN(pucStkNow, ARCH_STK_ALIGN_SIZE);
+ pabtctx = (PLW_VMM_ABORT_CTX)pucStkNow; /* 记录 PAGE_FAIL_CTX 位置 */
+ pucStkNow -= sizeof(LW_STACK); /* 向空栈方向移动一个堆栈空间 */
#endif
- pvmpagefailctx->PAGEFCTX_ptcb = ptcb;
- pvmpagefailctx->PAGEFCTX_ulRetAddr = ulRetAddr; /* 异常返回地址 */
- pvmpagefailctx->PAGEFCTX_ulAbortAddr = ulAbortAddr; /* 异常地址 (异常类型相关) */
- pvmpagefailctx->PAGEFCTX_abtInfo = *pabtInfo; /* 异常类型 */
- pvmpagefailctx->PAGEFCTX_archRegCtx = ptcb->TCB_archRegCtx;
- pvmpagefailctx->PAGEFCTX_iLastErrno = (errno_t)ptcb->TCB_ulLastError;
- pvmpagefailctx->PAGEFCTX_iKernelSpace = __KERNEL_SPACE_GET2(ptcb);
-
-#if LW_CFG_VMM_EN > 0
+ pabtctx->ABTCTX_ptcb = ptcb;
+ pabtctx->ABTCTX_ulRetAddr = ulRetAddr; /* 异常返回地址 */
+ pabtctx->ABTCTX_ulAbortAddr = ulAbortAddr; /* 异常地址 (异常类型相关) */
+ pabtctx->ABTCTX_abtInfo = *pabtInfo; /* 异常类型 */
+ pabtctx->ABTCTX_archRegCtx = ptcb->TCB_archRegCtx;
+ pabtctx->ABTCTX_iLastErrno = (errno_t)ptcb->TCB_ulLastError;
+ pabtctx->ABTCTX_iKernelSpace = __KERNEL_SPACE_GET2(ptcb);
+
pstkFailShell = archTaskCtxCreate(&ptcb->TCB_archRegCtx,
(PTHREAD_START_ROUTINE)pfuncHandler,
(PVOID)pabtctx,
@@ -1184,14 +1200,14 @@ VOID API_VmmAbortIsr (addr_t ulRetAddr,
archTaskCtxSetFp(pstkFailShell,
&ptcb->TCB_archRegCtx,
- &pvmpagefailctx->PAGEFCTX_archRegCtx); /* 保存 fp, 使 callstack 正常 */
+ &pabtctx->ABTCTX_archRegCtx); /* 保存 fp, 使 callstack 正常 */
_StackCheckGuard(ptcb); /* 堆栈警戒检查 */
__KERNEL_EXIT(); /* 退出内核 */
#if LW_CFG_CPU_FPU_EN > 0
- if (__PAGEFAILCTX_ABORT_TYPE(pvmpagefailctx) == LW_VMM_ABORT_TYPE_FPE) {
+ if (__ABTCTX_ABORT_TYPE(pabtctx) == LW_VMM_ABORT_TYPE_FPE) {
if (ptcb->TCB_ulOption & LW_OPTION_THREAD_USED_FP) { /* 如果为 FPU 异常 */
__ARCH_FPU_SAVE(ptcb->TCB_pvStackFP); /* 需要保存当前 FPU CTX */
}
@@ -1199,7 +1215,7 @@ VOID API_VmmAbortIsr (addr_t ulRetAddr,
#endif /* LW_CFG_CPU_FPU_EN > 0 */
#if LW_CFG_CPU_DSP_EN > 0
- if (__PAGEFAILCTX_ABORT_TYPE(pvmpagefailctx) == LW_VMM_ABORT_TYPE_DSPE) {
+ if (__ABTCTX_ABORT_TYPE(pabtctx) == LW_VMM_ABORT_TYPE_DSPE) {
if (ptcb->TCB_ulOption & LW_OPTION_THREAD_USED_DSP) { /* 如果为 DSP 异常 */
__ARCH_DSP_SAVE(ptcb->TCB_pvStackDSP); /* 需要保存当前 DSP CTX */
}
@@ -1207,6 +1223,36 @@ VOID API_VmmAbortIsr (addr_t ulRetAddr,
#endif /* LW_CFG_CPU_DSP_EN > 0 */
}
/*********************************************************************************************************
+** 函数名称: API_VmmAbortIsr
+** 功能描述: 当 MMU 产生访问失效时, 调用此函数(类似于中断服务函数)
+** 输 入 : ulRetAddr 异常返回地址
+** ulAbortAddr 异常地址 (异常类型相关)
+** pabtInfo 异常类型
+** ptcb 出现异常的线程控制块 (不能为 NULL)
+** 输 出 : NONE
+** 全局变量:
+** 调用模块:
+** 注 意 : 从 1.0.0.rc20 版本后, 此函数可以脱离 VMM 运行.
+**
+** 1. 构造缺页中断线程执行陷阱, 在陷阱中完成所有的页面操作, 如果失败, 线程自我销毁.
+** 2. 注意, 陷阱执行完毕后, 系统必须能够回到刚刚访问内存并产生异常的那条指令.
+** 3. 由于产生缺页中断时, 相关线程一定是就绪的, 所以这里不用加入调度器处理.
+
+ API 函数
+*********************************************************************************************************/
+LW_API
+VOID API_VmmAbortIsr (addr_t ulRetAddr,
+ addr_t ulAbortAddr,
+ PLW_VMM_ABORT pabtInfo,
+ PLW_CLASS_TCB ptcb)
+{
+#if LW_CFG_VMM_EN > 0
+ API_VmmAbortIsrEx(ulRetAddr, ulAbortAddr, pabtInfo, ptcb, __vmmAbortShell);
+#else
+ API_VmmAbortIsrEx(ulRetAddr, ulAbortAddr, pabtInfo, ptcb, __vmmAbortAccess);
+#endif /* LW_CFG_VMM_EN > 0 */
+}
+/*********************************************************************************************************
** 函数名称: API_VmmAbortStatus
** 功能描述: 系统访问中止状态.
** 输 入 : pvmms 系统状态变量
diff --git a/SylixOS/kernel/vmm/vmmSwap.h b/SylixOS/kernel/vmm/vmmSwap.h
index 6ba9788..30e5c9e 100644
--- a/SylixOS/kernel/vmm/vmmSwap.h
+++ b/SylixOS/kernel/vmm/vmmSwap.h
@@ -26,22 +26,9 @@
异常消息
*********************************************************************************************************/
-typedef struct {
- ARCH_REG_CTX PAGEFCTX_archRegCtx; /* 寄存器上下文 */
- addr_t PAGEFCTX_ulRetAddr; /* 异常返回地址 */
- addr_t PAGEFCTX_ulAbortAddr; /* 内存访问失效地址 */
- LW_VMM_ABORT PAGEFCTX_abtInfo; /* 异常类型 */
- PLW_CLASS_TCB PAGEFCTX_ptcb; /* 产生缺页中断的线程 */
-
- errno_t PAGEFCTX_iLastErrno; /* 返回时需要恢复的信息 */
- INT PAGEFCTX_iKernelSpace;
-} LW_VMM_PAGE_FAIL_CTX;
-typedef LW_VMM_PAGE_FAIL_CTX *PLW_VMM_PAGE_FAIL_CTX;
-
-#define __PAGEFAILCTX_SIZE_ALIGN ROUND_UP(sizeof(LW_VMM_PAGE_FAIL_CTX), sizeof(LW_STACK))
-
-#define __PAGEFAILCTX_ABORT_TYPE(pctx) (pctx->PAGEFCTX_abtInfo.VMABT_uiType)
-#define __PAGEFAILCTX_ABORT_METHOD(pctx) (pctx->PAGEFCTX_abtInfo.VMABT_uiMethod)
+#define __ABTCTX_SIZE_ALIGN ROUND_UP(sizeof(LW_VMM_ABORT_CTX), sizeof(LW_STACK))
+#define __ABTCTX_ABORT_TYPE(pctx) (pctx->ABTCTX_abtInfo.VMABT_uiType)
+#define __ABTCTX_ABORT_METHOD(pctx) (pctx->ABTCTX_abtInfo.VMABT_uiMethod)
/*********************************************************************************************************
加入裁剪支持
@@ -51,7 +38,6 @@ typedef LW_VMM_PAGE_FAIL_CTX *PLW_VMM_PAGE_FAIL_CTX;
/*********************************************************************************************************
缺页中断系统支持结构
*********************************************************************************************************/
-
typedef struct {
LW_LIST_LINE PAGEP_lineManage; /* area 链表 */
PLW_VMM_PAGE PAGEP_pvmpageVirtual; /* 回指虚拟页面控制块 */
diff --git a/SylixOS/kidvpn/kv_lib.c b/SylixOS/kidvpn/kv_lib.c
index e9521f5..5148d20 100644
--- a/SylixOS/kidvpn/kv_lib.c
+++ b/SylixOS/kidvpn/kv_lib.c
@@ -41,10 +41,7 @@
/* vnd/tap if name */
static char kv_vnd_ifname[IFNAMSIZ];
-/*********************************************************************************************************
- 裁剪控制
-*********************************************************************************************************/
-//#if LW_CFG_NET_EN > 0 && LW_CFG_NET_VNETDEV_EN > 0
+#if LW_CFG_NET_EN > 0 && LW_CFG_NET_VNETDEV_EN > 0
/* init vnd device */
int kv_lib_init (int vnd_id, const char *tap_name, int *s_fd, int *v_fd, UINT8 hwaddr[], int mtu)
@@ -317,11 +314,7 @@ struct kv_cli_node *kv_lib_cli_find (UINT8 hwaddr[], struct kv_cli_node *header
return (NULL);
}
-
-/*********************************************************************************************************
- 裁剪控制
-*********************************************************************************************************/
-//#endif /* #if LW_CFG_NET_EN > 0 && LW_CFG_NET_VNETDEV_EN > 0 */
+#endif /* #if LW_CFG_NET_EN > 0 && LW_CFG_NET_VNETDEV_EN > 0 */
/*
* end
*/
diff --git a/SylixOS/loader/elf/elf_loader.c b/SylixOS/loader/elf/elf_loader.c
index 883ffea..92fa260 100644
--- a/SylixOS/loader/elf/elf_loader.c
+++ b/SylixOS/loader/elf/elf_loader.c
@@ -161,6 +161,7 @@ static INT elfRelaRelocate (LW_LD_EXEC_MODULE *pmodule,
size_t stJmpTableItem;
Elf_Addr addrSymVal;
ULONG i;
+ BOOL bNoSymbol = LW_FALSE;
LD_DEBUG_MSG(("relocateSectionRela()\r\n"));
@@ -186,8 +187,9 @@ static INT elfRelaRelocate (LW_LD_EXEC_MODULE *pmodule,
pcSymName,
&addrSymVal,
LW_LD_SYM_ANY) < 0) { /* 查询对应符号的地址 */
- _ErrorHandle(ERROR_LOADER_NO_SYMBOL);
- return (PX_ERROR);
+ bNoSymbol = LW_TRUE;
+ prela++;
+ continue;
}
}
@@ -212,7 +214,13 @@ static INT elfRelaRelocate (LW_LD_EXEC_MODULE *pmodule,
prela++;
}
- return (ERROR_NONE);
+ if (bNoSymbol) {
+ _ErrorHandle(ERROR_LOADER_NO_SYMBOL);
+ return (PX_ERROR);
+
+ } else {
+ return (ERROR_NONE);
+ }
}
/*********************************************************************************************************
** 函数名称: elfRelRelocate
@@ -241,6 +249,7 @@ static INT elfRelRelocate (LW_LD_EXEC_MODULE *pmodule,
size_t stJmpTableItem;
Elf_Addr symVal;
ULONG i;
+ BOOL bNoSymbol = LW_FALSE;
LD_DEBUG_MSG(("relocateSectionRel()\r\n"));
@@ -266,8 +275,9 @@ static INT elfRelRelocate (LW_LD_EXEC_MODULE *pmodule,
pcSymName,
&symVal,
LW_LD_SYM_ANY) < 0) { /* 查询对应符号的地址 */
- _ErrorHandle(ERROR_LOADER_NO_SYMBOL);
- return (PX_ERROR);
+ bNoSymbol = LW_TRUE;
+ prel++;
+ continue;
}
}
@@ -292,7 +302,13 @@ static INT elfRelRelocate (LW_LD_EXEC_MODULE *pmodule,
prel++;
}
- return (ERROR_NONE);
+ if (bNoSymbol) {
+ _ErrorHandle(ERROR_LOADER_NO_SYMBOL);
+ return (PX_ERROR);
+
+ } else {
+ return (ERROR_NONE);
+ }
}
/*********************************************************************************************************
** 函数名称: elfSectionsRelocate
@@ -1578,6 +1594,7 @@ static INT elfPhdrRelocate (LW_LD_EXEC_MODULE *pmodule, ELF_DYN_DIR *pdyndir)
PCHAR pcBase = LW_NULL;
INT i;
+ BOOL bNoSymbol = LW_FALSE;
pcBase = (PCHAR)LW_LD_V2PADDR(addrMin,
pmodule->EMOD_pvBaseAddr,
@@ -1611,8 +1628,8 @@ static INT elfPhdrRelocate (LW_LD_EXEC_MODULE *pmodule, ELF_DYN_DIR *pdyndir)
pcSymName,
&addrSymVal,
LW_LD_SYM_ANY) < 0) { /* 查询对应符号的地址 */
- _ErrorHandle(ERROR_LOADER_NO_SYMBOL);
- return (PX_ERROR);
+ bNoSymbol = LW_TRUE;
+ continue;
}
}
@@ -1654,8 +1671,8 @@ static INT elfPhdrRelocate (LW_LD_EXEC_MODULE *pmodule, ELF_DYN_DIR *pdyndir)
pcSymName,
&addrSymVal,
LW_LD_SYM_ANY) < 0) { /* 查询对应符号的地址 */
- _ErrorHandle(ERROR_LOADER_NO_SYMBOL);
- return (PX_ERROR);
+ bNoSymbol = LW_TRUE;
+ continue;
}
}
@@ -1677,7 +1694,13 @@ static INT elfPhdrRelocate (LW_LD_EXEC_MODULE *pmodule, ELF_DYN_DIR *pdyndir)
}
}
- return (ERROR_NONE);
+ if (bNoSymbol) {
+ _ErrorHandle(ERROR_LOADER_NO_SYMBOL);
+ return (PX_ERROR);
+
+ } else {
+ return (ERROR_NONE);
+ }
}
/*********************************************************************************************************
** 函数名称: elfPhdrSymExport
diff --git a/SylixOS/loader/src/loader_vppatch.c b/SylixOS/loader/src/loader_vppatch.c
index d3a74ae..859df0f 100644
--- a/SylixOS/loader/src/loader_vppatch.c
+++ b/SylixOS/loader/src/loader_vppatch.c
@@ -2015,7 +2015,6 @@ static BOOL vprocTraverseSymCb (PVOID pvArg, PLW_SYMBOL psymbol, LW_LD_EXEC_MODU
if (ptsba->TSBA_pcAddr == psymbol->SYM_pcAddr) {
ptsba->TSBA_psymbol = psymbol;
ptsba->TSBA_bFound = LW_TRUE;
- ptsba->TSBA_pmod = pmod;
return (LW_TRUE);
}
@@ -2024,7 +2023,6 @@ static BOOL vprocTraverseSymCb (PVOID pvArg, PLW_SYMBOL psymbol, LW_LD_EXEC_MODU
if (ptsba->TSBA_stDistance > stDistance) {
ptsba->TSBA_stDistance = stDistance;
ptsba->TSBA_psymbol = psymbol;
- ptsba->TSBA_pmod = pmod;
}
}
@@ -2047,7 +2045,6 @@ static BOOL vprocTraverseKernelSymCb (PVOID pvArg, PLW_SYMBOL psymbol)
if (ptsba->TSBA_pcAddr == psymbol->SYM_pcAddr) {
ptsba->TSBA_psymbol = psymbol;
ptsba->TSBA_bFound = LW_TRUE;
- ptsba->TSBA_pmod = LW_NULL;
return (LW_TRUE);
}
@@ -2056,7 +2053,6 @@ static BOOL vprocTraverseKernelSymCb (PVOID pvArg, PLW_SYMBOL psymbol)
if (ptsba->TSBA_stDistance > stDistance) {
ptsba->TSBA_stDistance = stDistance;
ptsba->TSBA_psymbol = psymbol;
- ptsba->TSBA_pmod = LW_NULL;
}
}
@@ -2083,9 +2079,6 @@ INT API_ModuleAddr (PVOID pvAddr,
Dl_info *pdlinfo = (Dl_info *)pvDlinfo;
LW_LD_VPROC *pvproc = (LW_LD_VPROC *)pvVProc;
- LW_LD_EXEC_MODULE *pmodTemp;
- PLW_LIST_RING pringTemp;
-
LW_LD_TSB_ARG tsba;
if (!pvAddr || !pdlinfo) {
@@ -2099,46 +2092,77 @@ INT API_ModuleAddr (PVOID pvAddr,
tsba.TSBA_pmod = LW_NULL;
tsba.TSBA_stDistance = __LW_MODULE_MAX_DISTANCE;
- if (pvproc) {
+ if (pvproc) { /* 有进程控制块 */
+ PLW_LIST_RING pringTemp;
+
LW_VP_LOCK(pvproc);
+
pringTemp = pvproc->VP_ringModules;
+
if (pringTemp) {
- pmodTemp = _LIST_ENTRY(pringTemp, LW_LD_EXEC_MODULE, EMOD_ringModules);
- __moduleTraverseSym(pmodTemp, vprocTraverseSymCb, (PVOID)&tsba);
+ INT i;
+ PLW_SYMBOL psymbol;
+ PLW_LIST_LINE plineTemp;
+ LW_LD_EXEC_MODULE *pmodHead;
+ LW_LD_EXEC_MODULE *pmodTemp;
+
+ pmodHead = _LIST_ENTRY(pringTemp, LW_LD_EXEC_MODULE, EMOD_ringModules);
+
+ do {
+ pmodTemp = _LIST_ENTRY(pringTemp, LW_LD_EXEC_MODULE, EMOD_ringModules);
+
+ if ((pvAddr >= pmodTemp->EMOD_pvBaseAddr) &&
+ (pvAddr < (PVOID)((addr_t)pmodTemp->EMOD_pvBaseAddr + pmodTemp->EMOD_stLen))) {
+
+ tsba.TSBA_pmod = pmodTemp;
+
+ for (i = 0; i < pmodTemp->EMOD_ulSymHashSize; i++) {
+ for (plineTemp = pmodTemp->EMOD_psymbolHash[i];
+ plineTemp != LW_NULL;
+ plineTemp = _list_line_get_next(plineTemp)) {
+
+ psymbol = _LIST_ENTRY(plineTemp, LW_SYMBOL, SYM_lineManage);
+ if (vprocTraverseSymCb((PVOID)&tsba, psymbol, pmodTemp)) {
+ goto __most_suitable;
+ }
+ }
+ }
+
+ break;
+ }
+
+ pringTemp = _list_ring_get_next(pringTemp);
+ } while (pringTemp != &pmodHead->EMOD_ringModules);
}
+
+__most_suitable:
LW_VP_UNLOCK(pvproc);
}
- if (tsba.TSBA_bFound) {
- pdlinfo->dli_fname = tsba.TSBA_pmod->EMOD_pcModulePath;
- pdlinfo->dli_fbase = (void *)tsba.TSBA_pmod;
- pdlinfo->dli_sname = tsba.TSBA_psymbol->SYM_pcName;
- pdlinfo->dli_saddr = (void *)tsba.TSBA_psymbol->SYM_pcAddr;
- return (ERROR_NONE);
- }
-
- API_SymbolTraverse(vprocTraverseKernelSymCb, (PVOID)&tsba); /* 查找内核符号表 */
-
- if (tsba.TSBA_stDistance == __LW_MODULE_MAX_DISTANCE) {
- return (PX_ERROR);
- }
-
- if (tsba.TSBA_pmod) {
+ if (tsba.TSBA_pmod) { /* 找到了模块 */
pdlinfo->dli_fname = tsba.TSBA_pmod->EMOD_pcModulePath;
pdlinfo->dli_fbase = (void *)tsba.TSBA_pmod;
+
} else {
+ API_SymbolTraverse(vprocTraverseKernelSymCb, (PVOID)&tsba); /* 查找内核符号表 */
+
+ if (tsba.TSBA_stDistance == __LW_MODULE_MAX_DISTANCE) {
+ return (PX_ERROR);
+ }
+
pdlinfo->dli_fname = "kernel";
pdlinfo->dli_fbase = LW_NULL;
}
-
+
if (tsba.TSBA_psymbol) {
pdlinfo->dli_sname = tsba.TSBA_psymbol->SYM_pcName;
pdlinfo->dli_saddr = (void *)tsba.TSBA_psymbol->SYM_pcAddr;
+
} else {
pdlinfo->dli_sname = LW_NULL;
pdlinfo->dli_saddr = LW_NULL;
}
-
+
return (ERROR_NONE);
}
/*********************************************************************************************************
diff --git a/SylixOS/mktemp/application.mk b/SylixOS/mktemp/application.mk
index 9a873dc..14f6df5 100644
--- a/SylixOS/mktemp/application.mk
+++ b/SylixOS/mktemp/application.mk
@@ -52,6 +52,21 @@ $(target)_CFLAGS := $($(target)_COMMONFLAGS) $(ARCH_PIC_CFLAGS) $($(target)
$(target)_CXXFLAGS := $($(target)_COMMONFLAGS) $(ARCH_PIC_CFLAGS) $($(target)_DSYMBOL) $($(target)_INC_PATH) $($(target)_CXX_EXCEPT) $($(target)_CXXFLAGS)
#*********************************************************************************************************
+# NOTE:
+# On the mips platform, if the application adds "--no-undefined --ignore-unresolved-symbol,SYMBOL"
+# link parameters, The linker does not fill in the correct offset of GOT table for the jump code
+# of the SYMBOL function that the application calls. So we will link the application twice,
+# the first time will be adding the "--no-undefined --ignore-unresolved-symbol,SYMBOL" link parameter.
+# The first time link is only used to check the integrity of the symbol.
+# The second time link does not add the "--no-undefined --ignore-unresolved-symbol,SYMBOL"
+# link parameter to ensure the normal application is generated.
+#*********************************************************************************************************
+ifeq ($($(target)_NO_UNDEF_SYM), yes)
+ifeq (,$(findstring mips,$(ARCH)))
+$(target)_LINKFLAGS := $(TOOLCHAIN_NO_UNDEF_SYM_FLAGS) $($(target)_LINKFLAGS)
+endif
+endif
+#*********************************************************************************************************
# Targets
#*********************************************************************************************************
$(target)_EXE := $(OUTPATH)/$(LOCAL_TARGET_NAME)
@@ -118,6 +133,14 @@ $($(target)_EXE): $($(target)_OBJS) $($(target)_DEPEND_TARGET)
@mv $@.c6x $@
@rm -f $@_nm.txt $@_dis.txt
$(__POST_LINK_CMD)
+else ifeq ($(findstring mips,$(ARCH))_$($(target)_NO_UNDEF_SYM), mips_yes)
+$($(target)_EXE): $($(target)_OBJS) $($(target)_DEPEND_TARGET)
+ @rm -f $@
+ $(__PRE_LINK_CMD)
+ @$(__LD) $(__CPUFLAGS) $(ARCH_PIC_LDFLAGS) $(TOOLCHAIN_NO_UNDEF_SYM_FLAGS) $(__LINKFLAGS) $(__OBJS) $(__LIBRARIES) -o $@.tmp
+ @rm -f $@.tmp
+ $(__LD) $(__CPUFLAGS) $(ARCH_PIC_LDFLAGS) $(__LINKFLAGS) $(__OBJS) $(__LIBRARIES) -o $@
+ $(__POST_LINK_CMD)
else
$($(target)_EXE): $($(target)_OBJS) $($(target)_DEPEND_TARGET)
@rm -f $@
diff --git a/SylixOS/mktemp/bsp.mk b/SylixOS/mktemp/bsp.mk
index 543a397..85b2e5a 100644
--- a/SylixOS/mktemp/bsp.mk
+++ b/SylixOS/mktemp/bsp.mk
@@ -25,10 +25,10 @@
ifeq ($(BSP_SYMBOL_PATH),)
BSP_SYMBOL_PATH = SylixOS/bsp
-$(BSP_SYMBOL_PATH)/symbol.c: $(subst $(SPACE),\ ,$(SYLIXOS_BASE_PATH))/libsylixos/$(OUTDIR)/symbol.c $(BSP_SYMBOL_PATH)/symbol.h
+$(BSP_SYMBOL_PATH)/symbol.c: $(SYLIXOS_BASE_PATH)/libsylixos/$(OUTDIR)/symbol.c $(BSP_SYMBOL_PATH)/symbol.h
cp "$(SYLIXOS_BASE_PATH)/libsylixos/$(OUTDIR)/symbol.c" $(BSP_SYMBOL_PATH)/symbol.c
-$(BSP_SYMBOL_PATH)/symbol.h: $(subst $(SPACE),\ ,$(SYLIXOS_BASE_PATH))/libsylixos/$(OUTDIR)/symbol.h
+$(BSP_SYMBOL_PATH)/symbol.h: $(SYLIXOS_BASE_PATH)/libsylixos/$(OUTDIR)/symbol.h
cp "$(SYLIXOS_BASE_PATH)/libsylixos/$(OUTDIR)/symbol.h" $(BSP_SYMBOL_PATH)/symbol.h
endif
diff --git a/SylixOS/mktemp/cl6x.mk b/SylixOS/mktemp/cl6x.mk
index 3600a33..f761c90 100644
--- a/SylixOS/mktemp/cl6x.mk
+++ b/SylixOS/mktemp/cl6x.mk
@@ -70,6 +70,7 @@ TOOLCHAIN_GCOV_CFLAGS =
TOOLCHAIN_OMP_CFLAGS =
TOOLCHAIN_COMMONFLAGS =
TOOLCHAIN_ASFLAGS =
+TOOLCHAIN_NO_UNDEF_SYM_FLAGS =
TOOLCHAIN_AR_FLAGS = rq
TOOLCHAIN_STRIP_FLAGS =
diff --git a/SylixOS/mktemp/clear-vars.mk b/SylixOS/mktemp/clear-vars.mk
index aad36e6..9584fb2 100644
--- a/SylixOS/mktemp/clear-vars.mk
+++ b/SylixOS/mktemp/clear-vars.mk
@@ -94,6 +94,11 @@ LOCAL_CXXFLAGS :=
LOCAL_LINKFLAGS :=
#*********************************************************************************************************
+# Linker specific
+#*********************************************************************************************************
+LOCAL_NO_UNDEF_SYM := no
+
+#*********************************************************************************************************
# Command
#*********************************************************************************************************
LOCAL_PRE_LINK_CMD :=
diff --git a/SylixOS/mktemp/common.mk b/SylixOS/mktemp/common.mk
index cd879f6..6ce181a 100644
--- a/SylixOS/mktemp/common.mk
+++ b/SylixOS/mktemp/common.mk
@@ -122,6 +122,8 @@ $(target)_USE_GCOV := $(LOCAL_USE_GCOV)
$(target)_USE_OMP := $(LOCAL_USE_OMP)
$(target)_USE_EXTENSION := $(LOCAL_USE_EXTENSION)
+$(target)_NO_UNDEF_SYM := $(LOCAL_NO_UNDEF_SYM)
+
$(target)_PRE_LINK_CMD := $(LOCAL_PRE_LINK_CMD)
$(target)_POST_LINK_CMD := $(LOCAL_POST_LINK_CMD)
diff --git a/SylixOS/mktemp/gcc.mk b/SylixOS/mktemp/gcc.mk
index 0c2958d..4bb0b94 100644
--- a/SylixOS/mktemp/gcc.mk
+++ b/SylixOS/mktemp/gcc.mk
@@ -74,6 +74,7 @@ TOOLCHAIN_GCOV_CFLAGS = -fprofile-arcs -ftest-coverage
TOOLCHAIN_OMP_CFLAGS = -fopenmp
TOOLCHAIN_COMMONFLAGS = -Wall -fmessage-length=0 -fsigned-char -fno-short-enums -fno-strict-aliasing
TOOLCHAIN_ASFLAGS = -x assembler-with-cpp
+TOOLCHAIN_NO_UNDEF_SYM_FLAGS = @$(SYLIXOS_BASE_PATH)/libsylixos/$(OUTDIR)/symbol.ld
TOOLCHAIN_AR_FLAGS = -r
TOOLCHAIN_STRIP_FLAGS =
diff --git a/SylixOS/mktemp/gtest.mk b/SylixOS/mktemp/gtest.mk
index 8d525b0..f0951de 100644
--- a/SylixOS/mktemp/gtest.mk
+++ b/SylixOS/mktemp/gtest.mk
@@ -51,6 +51,11 @@ $(target)_ASFLAGS := $($(target)_COMMONFLAGS) $(ARCH_PIC_ASFLAGS) $(TOOLCHAI
$(target)_CFLAGS := $($(target)_COMMONFLAGS) $(ARCH_PIC_CFLAGS) $($(target)_DSYMBOL) $($(target)_INC_PATH) $($(target)_CFLAGS)
$(target)_CXXFLAGS := $($(target)_COMMONFLAGS) $(ARCH_PIC_CFLAGS) $($(target)_DSYMBOL) $($(target)_INC_PATH) $($(target)_CXX_EXCEPT) $($(target)_CXXFLAGS)
+ifeq ($($(target)_NO_UNDEF_SYM), yes)
+ifeq (,$(findstring mips,$(ARCH)))
+$(target)_LINKFLAGS := $(TOOLCHAIN_NO_UNDEF_SYM_FLAGS) $($(target)_LINKFLAGS)
+endif
+endif
#*********************************************************************************************************
# Targets
#*********************************************************************************************************
@@ -129,6 +134,14 @@ $($(target)_EXE): $($(target)_OBJS) $($(target)_DEPEND_TARGET)
@mv $@.c6x $@
@rm -f $@_nm.txt $@_dis.txt
$(__POST_LINK_CMD)
+else ifeq ($(findstring mips,$(ARCH))_$($(target)_NO_UNDEF_SYM), mips_yes)
+$($(target)_EXE): $($(target)_OBJS) $($(target)_DEPEND_TARGET)
+ @rm -f $@
+ $(__PRE_LINK_CMD)
+ @$(__LD) $(__CPUFLAGS) $(ARCH_PIC_LDFLAGS) $(TOOLCHAIN_NO_UNDEF_SYM_FLAGS) $(__LINKFLAGS) $(__OBJS) $(__LIBRARIES) -o $@.tmp
+ @rm -f $@.tmp
+ $(__LD) $(__CPUFLAGS) $(ARCH_PIC_LDFLAGS) $(__LINKFLAGS) $(__OBJS) $(__LIBRARIES) -o $@
+ $(__POST_LINK_CMD)
else
$($(target)_EXE): $($(target)_OBJS) $($(target)_DEPEND_TARGET)
@rm -f $@
diff --git a/SylixOS/mktemp/header.mk b/SylixOS/mktemp/header.mk
index d9688a2..a371dd2 100644
--- a/SylixOS/mktemp/header.mk
+++ b/SylixOS/mktemp/header.mk
@@ -72,6 +72,8 @@ BIAS = /
EMPTY =
SPACE = $(EMPTY) $(EMPTY)
+SYLIXOS_BASE_PATH := $(subst \,/,$(subst $(SPACE),\ ,$(SYLIXOS_BASE_PATH)))
+
__TARGET = $(word 3,$(subst $(BIAS),$(SPACE),$(@)))
__DEP = $(addprefix $(DEPPATH)/$(__TARGET)/, $(addsuffix .d, $(basename $(<))))
ifneq (,$(findstring cl6x,$(TOOLCHAIN_PREFIX)))
diff --git a/SylixOS/mktemp/mkdemo/application/application.mk b/SylixOS/mktemp/mkdemo/application/application.mk
index 60fcb8d..4d4a452 100644
--- a/SylixOS/mktemp/mkdemo/application/application.mk
+++ b/SylixOS/mktemp/mkdemo/application/application.mk
@@ -58,6 +58,11 @@ LOCAL_DEPEND_LIB :=
LOCAL_DEPEND_LIB_PATH :=
#*********************************************************************************************************
+# Linker specific
+#*********************************************************************************************************
+LOCAL_NO_UNDEF_SYM := no
+
+#*********************************************************************************************************
# C++ config
#*********************************************************************************************************
LOCAL_USE_CXX := no
diff --git a/SylixOS/mktemp/mkdemo/gtest/gtest.mk b/SylixOS/mktemp/mkdemo/gtest/gtest.mk
index 0f1b3f7..a51cfa5 100644
--- a/SylixOS/mktemp/mkdemo/gtest/gtest.mk
+++ b/SylixOS/mktemp/mkdemo/gtest/gtest.mk
@@ -61,6 +61,11 @@ LOCAL_DEPEND_LIB :=
LOCAL_DEPEND_LIB_PATH :=
#*********************************************************************************************************
+# Linker specific
+#*********************************************************************************************************
+LOCAL_NO_UNDEF_SYM := no
+
+#*********************************************************************************************************
# C++ config
#*********************************************************************************************************
LOCAL_USE_CXX := yes
diff --git a/SylixOS/mktemp/mkdemo/unit-test/unit-test.mk b/SylixOS/mktemp/mkdemo/unit-test/unit-test.mk
index b36dad7..32de45f 100644
--- a/SylixOS/mktemp/mkdemo/unit-test/unit-test.mk
+++ b/SylixOS/mktemp/mkdemo/unit-test/unit-test.mk
@@ -60,6 +60,11 @@ LOCAL_DEPEND_LIB :=
LOCAL_DEPEND_LIB_PATH :=
#*********************************************************************************************************
+# Linker specific
+#*********************************************************************************************************
+LOCAL_NO_UNDEF_SYM := no
+
+#*********************************************************************************************************
# C++ config
#*********************************************************************************************************
LOCAL_USE_CXX := no
diff --git a/SylixOS/mktemp/unit-test.mk b/SylixOS/mktemp/unit-test.mk
index f533201..a86ac4c 100644
--- a/SylixOS/mktemp/unit-test.mk
+++ b/SylixOS/mktemp/unit-test.mk
@@ -57,6 +57,11 @@ $(target)_ASFLAGS := $($(target)_COMMONFLAGS) $(ARCH_PIC_ASFLAGS) $(TOOLCHAI
$(target)_CFLAGS := $($(target)_COMMONFLAGS) $(ARCH_PIC_CFLAGS) $($(target)_DSYMBOL) $($(target)_INC_PATH) $($(target)_CFLAGS)
$(target)_CXXFLAGS := $($(target)_COMMONFLAGS) $(ARCH_PIC_CFLAGS) $($(target)_DSYMBOL) $($(target)_INC_PATH) $($(target)_CXX_EXCEPT) $($(target)_CXXFLAGS)
+ifeq ($($(target)_NO_UNDEF_SYM), yes)
+ifeq (,$(findstring mips,$(ARCH)))
+$(target)_LINKFLAGS := $(TOOLCHAIN_NO_UNDEF_SYM_FLAGS) $($(target)_LINKFLAGS)
+endif
+endif
#*********************************************************************************************************
# Targets
#*********************************************************************************************************
@@ -148,6 +153,19 @@ $1: $2 $3
$(__UNIT_TEST_POST_LINK_CMD)
endef
+else ifeq ($(findstring mips,$(ARCH))_$($(target)_NO_UNDEF_SYM), mips_yes)
+
+define CREATE_TARGET_EXE
+$1: $2 $3
+ @if [ ! -d "$(dir $1)" ]; then mkdir -p "$(dir $1)"; fi
+ @rm -f $1
+ $(__UNIT_TEST_PRE_LINK_CMD)
+ @$(__UNIT_TEST_LD) $(__UNIT_TEST_CPUFLAGS) $(ARCH_PIC_LDFLAGS) $(TOOLCHAIN_NO_UNDEF_SYM_FLAGS) $(__UNIT_TEST_LINKFLAGS) $2 $(__UNIT_TEST_LIBRARIES) -o $1.tmp
+ @rm -f $1.tmp
+ $(__UNIT_TEST_LD) $(__UNIT_TEST_CPUFLAGS) $(ARCH_PIC_LDFLAGS) $(__UNIT_TEST_LINKFLAGS) $2 $(__UNIT_TEST_LIBRARIES) -o $1
+ $(__UNIT_TEST_POST_LINK_CMD)
+endef
+
else
define CREATE_TARGET_EXE
diff --git a/SylixOS/net/lwip/flowctl/cor_flowctl.c b/SylixOS/net/lwip/flowctl/cor_flowctl.c
index 15a5e57..9457b20 100644
--- a/SylixOS/net/lwip/flowctl/cor_flowctl.c
+++ b/SylixOS/net/lwip/flowctl/cor_flowctl.c
@@ -1,3 +1,441 @@
+/**
+ * @file
+ * net flow control
+ * as much as possible compatible with different versions of LwIP
+ * Verification using sylixos(tm) real-time operating system
+ */
+
+/*
+ * Copyright (c) 2006-2017 SylixOS Group.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ * 4. This code has been or is applying for intellectual property protection
+ * and can only be used with acoinfo software products.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * Author: Han.hui <hanhui@acoinfo.com>
+ *
+ */
+
+#define __SYLIXOS_KERNEL
+#include "SylixOS.h"
+
+#if LW_CFG_NET_FLOWCTL_EN > 0
+
+#include "lwip/sys.h"
+#include "lwip/mem.h"
+#include "lwip/pbuf.h"
+#include "lwip/tcpip.h"
+#include "lwip/etharp.h"
+#include "cor_flowctl.h"
+
+#if (LW_CFG_NET_FLOWCTL_HZ < 2) || (LW_CFG_NET_FLOWCTL_HZ > 10)
+#error "LW_CFG_NET_FLOWCTL_HZ must set 2 ~ 10!"
+#endif
+
+/* packet input msg type */
+struct fcblk_inpkt_msg {
+ struct pbuf *p;
+ struct netif *inp;
+ netif_input_fn input;
+};
+
+/* all flow control block list */
+static LW_LIST_LINE_HEADER fcblk_list[FC_TYPE_MAX];
+
+/* packet input msg */
+static LW_HANDLE fcblk_msg;
+
+/* flow control block thread is init? */
+static LW_HANDLE fcblk_thd;
+
+/* flow control send queue */
+static void fcblk_send_q (struct fc_blk *fcblk, int all, int drop)
+{
+ PLW_LIST_RING pring;
+ struct fc_q *fcq;
+
+ while (fcblk->s_q &&
+ (all || (fcblk->s_rate == 0) ||
+ (fcblk->s_cur < fcblk->s_rate))) {
+ pring = _list_ring_get_prev(fcblk->s_q);
+ fcq = (struct fc_q *)pring;
+ fcblk->s_cur += fcq->p.pbuf.tot_len;
+ fcblk->cur_size -= fcq->p.pbuf.tot_len;
+ _List_Ring_Del(&fcq->ring, &fcblk->s_q);
+ if (!drop) {
+ fcblk->funcs->s_packet(fcq->priv, &fcq->p.pbuf, &fcq->addr);
+ }
+ pbuf_free(&fcq->p.pbuf);
+ }
+ fcblk->s_cur = 0; /* clear */
+}
+
+/* flow control recv queue */
+static void fcblk_recv_q (struct fc_blk *fcblk, int all, int drop)
+{
+ PLW_LIST_RING pring;
+ struct fc_q *fcq;
+
+ while (fcblk->r_q &&
+ (all || (fcblk->r_rate == 0) ||
+ (fcblk->r_cur < fcblk->r_rate))) {
+ pring = _list_ring_get_prev(fcblk->r_q);
+ fcq = (struct fc_q *)pring;
+ fcblk->r_cur += fcq->p.pbuf.tot_len;
+ fcblk->cur_size -= fcq->p.pbuf.tot_len;
+ _List_Ring_Del(&fcq->ring, &fcblk->r_q);
+ if (!drop) {
+ fcblk->funcs->r_packet(fcq->priv, &fcq->p.pbuf);
+ } else {
+ pbuf_free(&fcq->p.pbuf);
+ }
+ }
+ fcblk->r_cur = 0; /* clear */
+}
+
+/* flow control block buffer flush */
+static void fcblk_flush (void *id, int drop)
+{
+ int i;
+ PLW_LIST_LINE pline;
+ struct fc_blk *fcblk;
+
+ /* chang to pypass mode */
+ if (!drop) {
+ for (i = FC_TYPE_IPV4; i <= FC_TYPE_NETIF; i++) {
+ for (pline = fcblk_list[i]; pline != NULL; pline = _list_line_get_next(pline)) {
+ fcblk = (struct fc_blk *)pline;
+ if (fcblk->id == id) {
+ fcblk->bypass = 1;
+ }
+ }
+ }
+ }
+
+ /* tiger send packet */
+ for (i = FC_TYPE_NETIF; i >= FC_TYPE_IPV4; i--) {
+ for (pline = fcblk_list[i]; pline != NULL; pline = _list_line_get_next(pline)) {
+ fcblk = (struct fc_blk *)pline;
+ if (fcblk->id == id) {
+ fcblk_send_q(fcblk, 1, drop);
+ }
+ }
+ }
+
+ /* tiger recv packet */
+ for (i = FC_TYPE_IPV4; i <= FC_TYPE_NETIF; i++) {
+ for (pline = fcblk_list[i]; pline != NULL; pline = _list_line_get_next(pline)) {
+ fcblk = (struct fc_blk *)pline;
+ if (fcblk->id == id) {
+ fcblk_recv_q(fcblk, 1, drop);
+ }
+ }
+ }
+
+ /* chang to !pypass mode */
+ if (!drop) {
+ for (i = FC_TYPE_IPV4; i <= FC_TYPE_NETIF; i++) {
+ for (pline = fcblk_list[i]; pline != NULL; pline = _list_line_get_next(pline)) {
+ fcblk = (struct fc_blk *)pline;
+ if (fcblk->id == id) {
+ fcblk->bypass = 0;
+ }
+ }
+ }
+ }
+}
+
+/* flow control block thread timer */
+static void fcblk_timer (void)
+{
+ int i;
+ PLW_LIST_LINE pline;
+ struct fc_blk *fcblk;
+
+ FC_LOCK();
+
+ /* for low layer to high layer tiger send packet */
+ for (i = FC_TYPE_NETIF; i >= FC_TYPE_IPV4; i--) {
+ for (pline = fcblk_list[i]; pline != NULL; pline = _list_line_get_next(pline)) {
+ fcblk = (struct fc_blk *)pline;
+ fcblk_send_q(fcblk, 0, 0);
+ }
+ }
+
+ /* for high layer to low layer tiger recv packet */
+ for (i = FC_TYPE_IPV4; i <= FC_TYPE_NETIF; i++) {
+ for (pline = fcblk_list[i]; pline != NULL; pline = _list_line_get_next(pline)) {
+ fcblk = (struct fc_blk *)pline;
+ fcblk_recv_q(fcblk, 0, 0);
+ }
+ }
+
+ FC_UNLOCK();
+}
+
+/* flow control block thread
+ * Prevent tcpip queue data congestion, we use a thread instead a timer */
+static void fcblk_thread (void)
+{
+ struct fcblk_inpkt_msg msg;
+ ULONG err;
+ ULONG now, to = LW_TICK_HZ / LW_CFG_NET_FLOWCTL_HZ;
+ ULONG last = API_TimeGet();
+
+ for (;;) {
+ err = API_MsgQueueReceive(fcblk_msg, &msg, sizeof(struct fcblk_inpkt_msg), NULL, to);
+ if (err) {
+ LWIP_ASSERT("fcblk_thread msg error!", (err == ERROR_THREAD_WAIT_TIMEOUT));
+ fcblk_timer();
+ last = API_TimeGet();
+ continue;
+ }
+
+ /* check if we must call timer */
+ now = API_TimeGet();
+ if (now > last) {
+ if ((now - last) >= to) {
+ fcblk_timer();
+ last = now;
+ }
+
+ } else { /* timer overflow */
+ if (((ULONG_MAX - last) + now) >= to) {
+ fcblk_timer();
+ last = now;
+ }
+ }
+
+ FC_LOCK();
+
+ /* call input function */
+ if (msg.input(msg.p, msg.inp)) {
+ pbuf_free(msg.p);
+ }
+
+ FC_UNLOCK();
+ }
+}
+
+/* flow control pbuf free hook */
+static void fcblk_pbuf_free (struct pbuf *p)
+{
+ struct fc_q *fcq = _LIST_ENTRY(p, struct fc_q, p);
+
+ mem_free(fcq);
+}
+
+/* flow control pbuf alloc */
+static struct fc_q *fcblk_pbuf_alloc (struct pbuf *p)
+{
+ struct fc_q *fcq;
+ struct pbuf *ret;
+ u16_t reserve = ETH_PAD_SIZE + SIZEOF_VLAN_HDR;
+ u16_t tot_len = (u16_t)(reserve + p->tot_len);
+
+ fcq = (struct fc_q *)mem_malloc(ROUND_UP(sizeof(struct fc_q), MEM_ALIGNMENT) + tot_len);
+ if (fcq == NULL) {
+ return (NULL);
+ }
+
+ fcq->p.custom_free_function = fcblk_pbuf_free;
+
+ ret = pbuf_alloced_custom(PBUF_RAW, tot_len, PBUF_POOL, &fcq->p,
+ (char *)fcq + ROUND_UP(sizeof(struct fc_q), MEM_ALIGNMENT),
+ tot_len);
+ if (ret) {
+ pbuf_header(ret, (u16_t)-reserve);
+ pbuf_copy(ret, p);
+ }
+
+ return (fcq);
+}
+
+/* flow control block output */
+err_t fcblk_output (struct fc_blk *fcblk, struct pbuf *p, void *priv, const ip4_addr_t *ipaddr)
+{
+ struct fc_q *fcq;
+ ip_addr_t addr;
+
+ if (fcblk->bypass) {
+ ip_addr_copy_from_ip4(addr, *(ipaddr));
+ fcblk->funcs->s_packet(priv, p, &addr); /* send directly */
+ return (ERR_OK);
+ }
+
+ if (fcblk->s_rate == 0) { /* stop network output */
+ return (ERR_OK);
+ }
+
+ if (fcblk->s_q ||
+ ((fcblk->s_cur + p->tot_len) > fcblk->s_rate)) {
+ if ((fcblk->cur_size + p->tot_len) > fcblk->buf_size) {
+ return (ERR_MEM); /* buffer full, drop! */
+ }
+
+ fcq = fcblk_pbuf_alloc(p);
+ if (fcq == NULL) {
+ return (ERR_MEM);
+ }
+
+ fcq->priv = priv;
+ ip_addr_copy_from_ip4(fcq->addr, *(ipaddr));
+ _List_Ring_Add_Ahead(&fcq->ring, &fcblk->s_q); /* put to send queue */
+ fcblk->cur_size += p->tot_len;
+
+ } else {
+ ip_addr_copy_from_ip4(addr, *(ipaddr));
+ fcblk->funcs->s_packet(priv, p, &addr); /* send directly */
+ fcblk->s_cur += p->tot_len;
+ }
+
+ return (ERR_OK);
+}
+
+#if LWIP_IPV6
+/* flow control block output ipv6 */
+err_t fcblk_output_ip6 (struct fc_blk *fcblk, struct pbuf *p, void *priv, const ip6_addr_t *ipaddr)
+{
+ struct fc_q *fcq;
+ ip_addr_t addr;
+
+ if (fcblk->bypass) {
+ ip_addr_copy_from_ip6(addr, *(ipaddr));
+ fcblk->funcs->s_packet(priv, p, &addr); /* send directly */
+ return (ERR_OK);
+ }
+
+ if (fcblk->s_rate == 0) { /* stop network output */
+ return (ERR_OK);
+ }
+
+ if (fcblk->s_q ||
+ ((fcblk->s_cur + p->tot_len) > fcblk->s_rate)) {
+ if ((fcblk->cur_size + p->tot_len) > fcblk->buf_size) {
+ return (ERR_MEM); /* buffer full, drop! */
+ }
+
+ fcq = fcblk_pbuf_alloc(p);
+ if (fcq == NULL) {
+ return (ERR_MEM);
+ }
+
+ fcq->priv = priv;
+ ip_addr_copy_from_ip6(fcq->addr, *(ipaddr));
+ _List_Ring_Add_Ahead(&fcq->ring, &fcblk->s_q); /* put to send queue */
+ fcblk->cur_size += p->tot_len;
+
+ } else {
+ ip_addr_copy_from_ip6(addr, *(ipaddr));
+ fcblk->funcs->s_packet(priv, p, &addr); /* send directly */
+ fcblk->s_cur += p->tot_len;
+ }
+
+ return (ERR_OK);
+}
+#endif /* LWIP_IPV6 */
+
+/* flow control block recv */
+err_t fcblk_input (struct fc_blk *fcblk, struct pbuf *p, void *priv)
+{
+ struct fc_q *fcq;
+
+ if (fcblk->bypass) {
+ fcblk->funcs->r_packet(priv, p); /* recv directly */
+ return (ERR_OK);
+ }
+
+ if (fcblk->r_rate == 0) { /* stop network input */
+ pbuf_free(p); /* free input pbuf */
+ return (ERR_OK);
+ }
+
+ if (fcblk->r_q ||
+ ((fcblk->r_cur + p->tot_len) > fcblk->r_rate)) {
+ if ((fcblk->cur_size + p->tot_len) > fcblk->buf_size) {
+ return (ERR_MEM); /* buffer full, drop! */
+ }
+
+ fcq = fcblk_pbuf_alloc(p);
+ if (fcq == NULL) {
+ return (ERR_MEM);
+ }
+
+ pbuf_free(p); /* free input pbuf */
+ fcq->priv = priv;
+ _List_Ring_Add_Ahead(&fcq->ring, &fcblk->r_q);
+ fcblk->cur_size += p->tot_len;
+
+ } else {
+ fcblk->funcs->r_packet(priv, p); /* recv directly */
+ fcblk->r_cur += p->tot_len;
+ }
+
+ return (ERR_OK);
+}
+
+/* flow control init */
+static void fcblk_init (void)
+{
+ if (fcblk_msg == LW_HANDLE_INVALID) {
+ fcblk_msg = API_MsgQueueCreate("fc_msg", LW_CFG_LWIP_POOL_SIZE, sizeof(struct fcblk_inpkt_msg), LW_OPTION_DEFAULT, NULL);
+ }
+
+ if (fcblk_thd == LW_HANDLE_INVALID) {
+ fcblk_thd = sys_thread_new("t_flowctl", (lwip_thread_fn)fcblk_thread, NULL, TCPIP_THREAD_STACKSIZE, TCPIP_THREAD_PRIO);
+ }
+}
+
+/* flow control packet input */
+err_t fcblk_inpkt (struct pbuf *p, struct netif *inp, netif_input_fn input_fn)
+{
+ struct fcblk_inpkt_msg msg;
+
+ msg.p = p;
+ msg.inp = inp;
+ msg.input = input_fn;
+ if (API_MsgQueueSend(fcblk_msg, &msg, sizeof(struct fcblk_inpkt_msg))) {
+ return (ERR_BUF);
+ }
+ return (ERR_OK);
+}
+
+/* flow control block start */
+void fcblk_start (struct fc_blk *fcblk)
+{
+ _List_Line_Add_Ahead(&fcblk->list, &fcblk_list[fcblk->type]); /* add to timer list */
+ fcblk_init();
+}
+
+/* flow control stop */
+void fcblk_stop (struct fc_blk *fcblk, int drop)
+{
+ _List_Line_Del(&fcblk->list, &fcblk_list[fcblk->type]); /* delete from timer list */
+ fcblk_flush(fcblk->id, drop);
+}
+
+#endif /* LW_CFG_NET_FLOWCTL_EN > 0 */
/*
- * This file NOT include in open source version.
+ * end
*/
diff --git a/SylixOS/net/lwip/flowctl/cor_flowctl.h b/SylixOS/net/lwip/flowctl/cor_flowctl.h
index 15a5e57..e081678 100644
--- a/SylixOS/net/lwip/flowctl/cor_flowctl.h
+++ b/SylixOS/net/lwip/flowctl/cor_flowctl.h
@@ -1,3 +1,114 @@
+/**
+ * @file
+ * net flow control
+ * as much as possible compatible with different versions of LwIP
+ * Verification using sylixos(tm) real-time operating system
+ */
+
+/*
+ * Copyright (c) 2006-2017 SylixOS Group.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ * 4. This code has been or is applying for intellectual property protection
+ * and can only be used with acoinfo software products.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * Author: Han.hui <hanhui@acoinfo.com>
+ *
+ */
+
+#ifndef __COR_FLOWCTL_H
+#define __COR_FLOWCTL_H
+
+#include "lwip/pbuf.h"
+#include "lwip/tcpip.h"
+
+/* flow control lock */
+#define FC_LOCK() \
+ if (lock_tcpip_core) { \
+ LOCK_TCPIP_CORE(); \
+ }
+#define FC_UNLOCK() \
+ if (lock_tcpip_core) { \
+ UNLOCK_TCPIP_CORE(); \
+ }
+
+/* flow control rate */
+typedef UINT64 fc_rate_t;
+
+/* flow control buffer queue node */
+struct fc_q {
+ LW_LIST_RING ring;/* ring list */
+ void *priv; /* send or recv priv struct */
+ ip_addr_t addr; /* send addr */
+ struct pbuf_custom p; /* packet */
+};
+
+#define FC_TYPE_IPV4 0 /* ipv4 flow control type */
+#define FC_TYPE_IPV6 1 /* ipv6 flow control type */
+#define FC_TYPE_NETIF 2 /* netif flow control type */
+#define FC_TYPE_MAX 3 /* max entry of type queue */
+
+/* flow control block functions */
+struct fc_funcs {
+ /* s_packet function must do not delete pbuf always */
+ void (*s_packet)(void *priv, struct pbuf *p, ip_addr_t *addr);
+ /* r_packet function must delete pbuf always */
+ void (*r_packet)(void *priv, struct pbuf *p);
+};
+
+/* flow control block */
+struct fc_blk {
+ LW_LIST_LINE list; /* flow control timer list */
+ u_char type; /* FC_TYPE_IPV4 / FC_TYPE_IPV6 / FC_TYPE_NETIF */
+ u_char bypass; /* bypass mode */
+ LW_LIST_RING_HEADER s_q; /* send queue */
+ LW_LIST_RING_HEADER r_q; /* recv queue */
+ fc_rate_t s_cur; /* this sample time send packet bytes */
+ fc_rate_t r_cur; /* this sample time recv packet bytes */
+ fc_rate_t s_rate; /* send rate (per timeouts tick) */
+ fc_rate_t r_rate; /* recv rate (per timeouts tick) */
+ size_t cur_size; /* current buffer size */
+ size_t buf_size; /* total buffer size of each fcblk */
+ const struct fc_funcs *funcs; /* send and recv functions */
+ void *id; /* identifier */
+};
+
+/* flow control thread input queue */
+err_t fcblk_inpkt(struct pbuf *p, struct netif *inp, netif_input_fn input_fn);
+
+/* flow control block input output funcs */
+err_t fcblk_output(struct fc_blk *fcblk, struct pbuf *p, void *priv, const ip4_addr_t *ipaddr);
+#if LWIP_IPV6
+err_t fcblk_output_ip6(struct fc_blk *fcblk, struct pbuf *p, void *priv, const ip6_addr_t *ipaddr);
+#endif
+err_t fcblk_input(struct fc_blk *fcblk, struct pbuf *p, void *priv);
+
+/* flow control block add or delete */
+void fcblk_start(struct fc_blk *fcblk);
+void fcblk_stop(struct fc_blk *fcblk, int drop);
+
+#endif /* __COR_FLOWCTL_H */
/*
- * This file NOT include in open source version.
+ * end
*/
diff --git a/SylixOS/net/lwip/flowctl/ip4_flowctl.c b/SylixOS/net/lwip/flowctl/ip4_flowctl.c
index 15a5e57..f12a92b 100644
--- a/SylixOS/net/lwip/flowctl/ip4_flowctl.c
+++ b/SylixOS/net/lwip/flowctl/ip4_flowctl.c
@@ -1,3 +1,499 @@
+/**
+ * @file
+ * net flow control
+ * as much as possible compatible with different versions of LwIP
+ * Verification using sylixos(tm) real-time operating system
+ */
+
+/*
+ * Copyright (c) 2006-2017 SylixOS Group.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ * 4. This code has been or is applying for intellectual property protection
+ * and can only be used with acoinfo software products.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * Author: Han.hui <hanhui@acoinfo.com>
+ *
+ */
+
+#define __SYLIXOS_KERNEL
+#include "SylixOS.h"
+
+#if LW_CFG_NET_FLOWCTL_EN > 0
+
+#include "net/if.h"
+#include "lwip/ip.h"
+#include "lwip/inet.h"
+#include "lwip/netif.h"
+#include "lwip/prot/udp.h"
+#include "lwip/prot/tcp.h"
+#include "net_flowctl.h"
+
+/* netif flow control funcs */
+extern err_t fcnet_netif_output(struct netif *netif, struct pbuf *p,
+ const ip4_addr_t *ipaddr);
+
+/* ipv4 flow control match */
+static struct fc_blk *fcipv4_match (struct fc_dev *fcdev, struct pbuf *p, int send, s16_t ip_hdr_offset)
+{
+ u16_t iphdr_len;
+ u8_t proto;
+ struct ip_hdr *iphdr;
+ struct tcp_hdr *tcphdr;
+ struct udp_hdr *udphdr;
+ struct fc_ipv4 *fcipv4;
+ ip4_addr_t ipaddr_hbo;
+ u16_t port_hbo;
+ PLW_LIST_LINE pline;
+
+ iphdr = (struct ip_hdr *)((char *)p->payload + ip_hdr_offset);
+ iphdr_len = (u16_t)(IPH_HL(iphdr) << 2);
+ if (p->len < (ip_hdr_offset + iphdr_len)) {
+ return (NULL);
+ }
+
+ ipaddr_hbo.addr = (send) ? PP_NTOHL(iphdr->dest.addr) : PP_NTOHL(iphdr->src.addr);
+
+ proto = IPH_PROTO(iphdr);
+ switch (proto) {
+
+ case IP_PROTO_UDP:
+ case IP_PROTO_UDPLITE:
+ proto = IP_PROTO_UDP;
+ udphdr = (struct udp_hdr *)((char *)p->payload + ip_hdr_offset + iphdr_len);
+ if (p->len < (ip_hdr_offset + iphdr_len + UDP_HLEN)) {
+ return (NULL);
+ }
+ port_hbo = (send) ? PP_NTOHS(udphdr->src) : PP_NTOHS(udphdr->dest);
+ break;
+
+ case IP_PROTO_TCP:
+ tcphdr = (struct tcp_hdr *)((char *)p->payload + ip_hdr_offset + iphdr_len);
+ if (p->len < (ip_hdr_offset + iphdr_len + TCP_HLEN)) {
+ return (NULL);
+ }
+ port_hbo = (send) ? PP_NTOHS(tcphdr->src) : PP_NTOHS(tcphdr->dest);
+ break;
+
+ default:
+ proto = 0;
+ port_hbo = 0;
+ break;
+ }
+
+ for (pline = fcdev->fcd_list[FC_TYPE_IPV4];
+ pline != NULL;
+ pline = _list_line_get_next(pline)) {
+ fcipv4 = _LIST_ENTRY(pline, struct fc_ipv4, list);
+ if (!fcipv4->enable) {
+ continue;
+ }
+ if ((ipaddr_hbo.addr >= fcipv4->start_hbo.addr) &&
+ (ipaddr_hbo.addr <= fcipv4->end_hbo.addr)) {
+ if (fcipv4->proto == 0) {
+ return (&fcipv4->fcblk);
+
+ } else if (fcipv4->proto == proto) {
+ if ((proto == IP_PROTO_UDP) || (proto == IP_PROTO_TCP)) {
+ if ((port_hbo >= fcipv4->s_port_hbo) && (port_hbo <= fcipv4->e_port_hbo)) {
+ return (&fcipv4->fcblk);
+ }
+
+ } else {
+ return (&fcipv4->fcblk);
+ }
+ }
+ }
+ }
+
+ return (NULL);
+}
+
+/* ipv4 flow control send */
+static void fcipv4_netif_send (void *priv, struct pbuf *p, ip_addr_t *addr)
+{
+ struct fc_dev *fcdev = (struct fc_dev *)priv;
+
+ fcnet_netif_output(fcdev->netif, p, ip_2_ip4(addr)); /* send to fcnet layer */
+}
+
+/* ipv4 flow control recv */
+static void fcipv4_netif_recv (void *priv, struct pbuf *p)
+{
+ struct fc_dev *fcdev = (struct fc_dev *)priv;
+
+ if (fcnet_netif_tcpip_input(fcdev, p, fcdev->netif)) {
+ pbuf_free(p);
+ }
+}
+
+/* ipv4 netif flow control output */
+err_t fcipv4_netif_output (struct netif *netif, struct pbuf *p,
+ const ip4_addr_t *ipaddr)
+{
+ struct fc_dev *fcdev = NETIF_FCDEV(netif);
+ struct fc_blk *fcblk;
+
+ fcblk = fcipv4_match(fcdev, p, 1, 0);
+ if (fcblk) {
+ return (fcblk_output(fcblk, p, fcdev, ipaddr)); /* output flow control output queue */
+
+ } else {
+ return (fcnet_netif_output(netif, p, ipaddr)); /* send to fcnet layer */
+ }
+}
+
+/* ipv4 flow control input */
+err_t fcipv4_netif_input (struct pbuf *p, struct netif *netif, s16_t ip_hdr_offset)
+{
+ struct fc_dev *fcdev = NETIF_FCDEV(netif);
+ struct fc_blk *fcblk;
+
+ fcblk = fcipv4_match(fcdev, p, 0, ip_hdr_offset);
+ if (fcblk) {
+ return (fcblk_input(fcblk, p, fcdev)); /* input flow control input queue */
+
+ } else {
+ return (fcnet_netif_tcpip_input(fcdev, p, netif));
+ }
+}
+
+/* ipv4 flow control create */
+int fcipv4_rule_create (const char *ifname, const ip4_addr_t *start, const ip4_addr_t *end,
+ u_char proto, u_short s_port, u_short e_port, u_char enable,
+ fc_rate_t s_rate, fc_rate_t r_rate, size_t bsize)
+{
+ static const struct fc_funcs fcipv4_funcs = {
+ fcipv4_netif_send,
+ fcipv4_netif_recv
+ };
+
+ struct fc_dev *fcdev;
+ struct fc_ipv4 *fcipv4;
+
+ fcdev = fcnet_netif_searh(ifname);
+ if (fcdev == NULL) {
+ return (-1);
+ }
+
+ fcipv4 = (struct fc_ipv4 *)mem_malloc(sizeof(struct fc_ipv4));
+ if (fcipv4 == NULL) {
+ return (-2);
+ }
+ lib_bzero(fcipv4, sizeof(struct fc_ipv4));
+
+ fcipv4->enable = enable;
+ fcipv4->start_hbo.addr = PP_NTOHL(start->addr);
+ fcipv4->end_hbo.addr = PP_NTOHL(end->addr);
+ fcipv4->proto = proto;
+ fcipv4->s_port_hbo = PP_NTOHS(s_port);
+ fcipv4->e_port_hbo = PP_NTOHS(e_port);
+
+ fcipv4->fcblk.type = FC_TYPE_IPV4;
+ fcipv4->fcblk.s_rate = s_rate;
+ fcipv4->fcblk.r_rate = r_rate;
+ fcipv4->fcblk.buf_size = bsize;
+ fcipv4->fcblk.funcs = &fcipv4_funcs;
+
+ _List_Line_Add_Ahead(&fcipv4->list, &fcdev->fcd_list[FC_TYPE_IPV4]);
+ if (fcdev->netif) {
+ fcblk_start(&fcipv4->fcblk);
+ }
+
+ return (0);
+}
+
+/* ipv4 flow control delete */
+int fcipv4_rule_delete (const char *ifname, const ip4_addr_t *start, const ip4_addr_t *end,
+ u_char proto, u_short s_port, u_short e_port)
+{
+ struct fc_dev *fcdev;
+ struct fc_ipv4 *fcipv4;
+ PLW_LIST_LINE pline;
+ ip4_addr_t start_hbo, end_hbo;
+ u_short s_port_hbo, e_port_hbo;
+
+ fcdev = fcnet_netif_searh(ifname);
+ if (fcdev == NULL) {
+ return (-1);
+ }
+
+ start_hbo.addr = PP_NTOHL(start->addr);
+ end_hbo.addr = PP_NTOHL(end->addr);
+ s_port_hbo = PP_NTOHS(s_port);
+ e_port_hbo = PP_NTOHS(e_port);
+
+ for (pline = fcdev->fcd_list[FC_TYPE_IPV4];
+ pline != NULL;
+ pline = _list_line_get_next(pline)) {
+ fcipv4 = _LIST_ENTRY(pline, struct fc_ipv4, list);
+ if ((fcipv4->start_hbo.addr == start_hbo.addr) &&
+ (fcipv4->end_hbo.addr == end_hbo.addr) && (fcipv4->proto == proto) &&
+ (fcipv4->s_port_hbo == s_port_hbo) && (fcipv4->e_port_hbo == e_port_hbo)) {
+ break;
+ }
+ }
+
+ if (pline) {
+ _List_Line_Del(&fcipv4->list, &fcdev->fcd_list[FC_TYPE_IPV4]);
+ if (fcdev->netif) {
+ fcblk_stop(&fcipv4->fcblk, 0);
+ }
+ mem_free(fcipv4);
+ return (0);
+ }
+
+ return (-1);
+}
+
+/* ipv4 flow control change */
+int fcipv4_rule_change (const char *ifname, const ip4_addr_t *start, const ip4_addr_t *end,
+ u_char proto, u_short s_port, u_short e_port, u_char enable,
+ fc_rate_t s_rate, fc_rate_t r_rate, size_t bsize)
+{
+ struct fc_dev *fcdev;
+ struct fc_ipv4 *fcipv4;
+ PLW_LIST_LINE pline;
+ ip4_addr_t start_hbo, end_hbo;
+ u_short s_port_hbo, e_port_hbo;
+
+ fcdev = fcnet_netif_searh(ifname);
+ if (fcdev == NULL) {
+ return (-1);
+ }
+
+ start_hbo.addr = PP_NTOHL(start->addr);
+ end_hbo.addr = PP_NTOHL(end->addr);
+ s_port_hbo = PP_NTOHS(s_port);
+ e_port_hbo = PP_NTOHS(e_port);
+
+ for (pline = fcdev->fcd_list[FC_TYPE_IPV4];
+ pline != NULL;
+ pline = _list_line_get_next(pline)) {
+ fcipv4 = _LIST_ENTRY(pline, struct fc_ipv4, list);
+ if ((fcipv4->start_hbo.addr == start_hbo.addr) &&
+ (fcipv4->end_hbo.addr == end_hbo.addr) && (fcipv4->proto == proto) &&
+ (fcipv4->s_port_hbo == s_port_hbo) && (fcipv4->e_port_hbo == e_port_hbo)) {
+ break;
+ }
+ }
+
+ if (pline) {
+ fcipv4->enable = enable;
+ fcipv4->fcblk.s_rate = s_rate;
+ fcipv4->fcblk.r_rate = r_rate;
+ fcipv4->fcblk.buf_size = bsize;
+ return (0);
+ }
+
+ return (-1);
+}
+
+/* ipv4 flow control get */
+int fcipv4_rule_get (const char *ifname, const ip4_addr_t *start, const ip4_addr_t *end,
+ u_char proto, u_short s_port, u_short e_port, u_char *enable,
+ fc_rate_t *s_rate, fc_rate_t *r_rate, size_t *bsize)
+{
+ struct fc_dev *fcdev;
+ struct fc_ipv4 *fcipv4;
+ PLW_LIST_LINE pline;
+ ip4_addr_t start_hbo, end_hbo;
+ u_short s_port_hbo, e_port_hbo;
+
+ fcdev = fcnet_netif_searh(ifname);
+ if (fcdev == NULL) {
+ return (-1);
+ }
+
+ start_hbo.addr = PP_NTOHL(start->addr);
+ end_hbo.addr = PP_NTOHL(end->addr);
+ s_port_hbo = PP_NTOHS(s_port);
+ e_port_hbo = PP_NTOHS(e_port);
+
+ for (pline = fcdev->fcd_list[FC_TYPE_IPV4];
+ pline != NULL;
+ pline = _list_line_get_next(pline)) {
+ fcipv4 = _LIST_ENTRY(pline, struct fc_ipv4, list);
+ if ((fcipv4->start_hbo.addr == start_hbo.addr) &&
+ (fcipv4->end_hbo.addr == end_hbo.addr) && (fcipv4->proto == proto) &&
+ (fcipv4->s_port_hbo == s_port_hbo) && (fcipv4->e_port_hbo == e_port_hbo)) {
+ break;
+ }
+ }
+
+ if (pline) {
+ if (enable) {
+ *enable = fcipv4->enable;
+ }
+ if (s_rate) {
+ *s_rate = fcipv4->fcblk.s_rate;
+ }
+ if (r_rate) {
+ *r_rate = fcipv4->fcblk.r_rate;
+ }
+ if (bsize) {
+ *bsize = fcipv4->fcblk.buf_size;
+ }
+ return (0);
+ }
+
+ return (-1);
+}
+
+/* ipv4 flow control search */
+int fcipv4_rule_search (const char *ifname, const ip4_addr_t *ipaddr,
+ u_char proto, u_short port, u_char *enable,
+ fc_rate_t *s_rate, fc_rate_t *r_rate, size_t *bsize)
+{
+ struct fc_dev *fcdev;
+ struct fc_ipv4 *fcipv4;
+ PLW_LIST_LINE pline;
+ ip4_addr_t ipaddr_hbo;
+ u_short port_hbo;
+
+ fcdev = fcnet_netif_searh(ifname);
+ if (fcdev == NULL) {
+ return (-1);
+ }
+
+ ipaddr_hbo.addr = PP_NTOHL(ipaddr->addr);
+ port_hbo = PP_NTOHS(port);
+
+ for (pline = fcdev->fcd_list[FC_TYPE_IPV4];
+ pline != NULL;
+ pline = _list_line_get_next(pline)) {
+ fcipv4 = _LIST_ENTRY(pline, struct fc_ipv4, list);
+ if ((fcipv4->start_hbo.addr <= ipaddr_hbo.addr) &&
+ (fcipv4->end_hbo.addr >= ipaddr_hbo.addr) && (fcipv4->proto == proto) &&
+ (fcipv4->s_port_hbo <= port_hbo) && (fcipv4->e_port_hbo >= port_hbo)) {
+ break;
+ }
+ }
+
+ if (pline) {
+ if (enable) {
+ *enable = fcipv4->enable;
+ }
+ if (s_rate) {
+ *s_rate = fcipv4->fcblk.s_rate;
+ }
+ if (r_rate) {
+ *r_rate = fcipv4->fcblk.r_rate;
+ }
+ if (bsize) {
+ *bsize = fcipv4->fcblk.buf_size;
+ }
+ return (0);
+ }
+
+ return (-1);
+}
+
+/* ipv4 flow control delete all in netif */
+void fcipv4_rule_delif (struct fc_dev *fcdev)
+{
+ struct fc_ipv4 *fcipv4;
+
+ while (fcdev->fcd_list[FC_TYPE_IPV4]) {
+ fcipv4 = _LIST_ENTRY(fcdev->fcd_list[FC_TYPE_IPV4], struct fc_ipv4, list);
+ _List_Line_Del(&fcipv4->list, &fcdev->fcd_list[FC_TYPE_IPV4]);
+ if (fcdev->netif) {
+ fcblk_stop(&fcipv4->fcblk, 0);
+ }
+ mem_free(fcipv4);
+ }
+}
+
+/* ipv4 flow control walk call back */
+static void fcipv4_rule_traversal_net (struct fc_dev *fcdev,
+ VOIDFUNCPTR func, void *arg0, void *arg1,
+ void *arg2, void *arg3, void *arg4)
+{
+ struct fc_ipv4 *fcipv4;
+ PLW_LIST_LINE pline;
+
+ for (pline = fcdev->fcd_list[FC_TYPE_IPV4];
+ pline != NULL;
+ pline = _list_line_get_next(pline)) {
+ fcipv4 = _LIST_ENTRY(pline, struct fc_ipv4, list);
+ func(fcdev, fcipv4, arg0, arg1, arg2, arg3, arg4);
+ }
+}
+
+/* ipv4 flow control walk */
+void fcipv4_rule_traversal (VOIDFUNCPTR func, void *arg0, void *arg1,
+ void *arg2, void *arg3, void *arg4)
+{
+ fcnet_rule_traversal(fcipv4_rule_traversal_net, (void *)func, arg0, arg1, arg2, arg3, arg4);
+}
+
+/* ipv4 flow control cnt */
+static void fcipv4_counter (struct fc_dev *fcdev, struct fc_ipv4 *fcipv4, int *cnt)
+{
+ (*cnt) += 1;
+}
+
+/* ipv4 flow control total num */
+void fcipv4_total_entry (unsigned int *cnt)
+{
+ int count = 0;
+
+ fcipv4_rule_traversal(fcipv4_counter, &count, NULL, NULL, NULL, NULL);
+ if (cnt) {
+ *cnt = count;
+ }
+}
+
+/* ipv4 flow control netif attach */
+void fcipv4_netif_attach (struct fc_dev *fcdev)
+{
+ struct fc_ipv4 *fcipv4;
+ PLW_LIST_LINE pline;
+
+ for (pline = fcdev->fcd_list[FC_TYPE_IPV4];
+ pline != NULL;
+ pline = _list_line_get_next(pline)) {
+ fcipv4 = _LIST_ENTRY(pline, struct fc_ipv4, list);
+ fcblk_start(&fcipv4->fcblk);
+ }
+}
+
+/* ipv4 flow control netif detach */
+void fcipv4_netif_detach (struct fc_dev *fcdev)
+{
+ struct fc_ipv4 *fcipv4;
+ PLW_LIST_LINE pline;
+
+ for (pline = fcdev->fcd_list[FC_TYPE_IPV4];
+ pline != NULL;
+ pline = _list_line_get_next(pline)) {
+ fcipv4 = _LIST_ENTRY(pline, struct fc_ipv4, list);
+ fcblk_stop(&fcipv4->fcblk, 1);
+ }
+}
+
+#endif /* LW_CFG_NET_FLOWCTL_EN > 0 */
/*
- * This file NOT include in open source version.
+ * end
*/
diff --git a/SylixOS/net/lwip/flowctl/ip4_flowctl.h b/SylixOS/net/lwip/flowctl/ip4_flowctl.h
index 15a5e57..5ac26e1 100644
--- a/SylixOS/net/lwip/flowctl/ip4_flowctl.h
+++ b/SylixOS/net/lwip/flowctl/ip4_flowctl.h
@@ -1,3 +1,94 @@
+/**
+ * @file
+ * net flow control
+ * as much as possible compatible with different versions of LwIP
+ * Verification using sylixos(tm) real-time operating system
+ */
+
+/*
+ * Copyright (c) 2006-2017 SylixOS Group.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ * 4. This code has been or is applying for intellectual property protection
+ * and can only be used with acoinfo software products.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * Author: Han.hui <hanhui@acoinfo.com>
+ *
+ */
+
+#ifndef __IP4_FLOWCTL_H
+#define __IP4_FLOWCTL_H
+
+#include "cor_flowctl.h"
+
+struct fc_dev;
+
+/* flow control ipv4 */
+struct fc_ipv4 {
+ /* common member */
+ struct fc_blk fcblk;
+
+ /* ipv4 member */
+ LW_LIST_LINE list;
+ u_char enable;
+ ip4_addr_t start_hbo; /* ip range (NOTICE: this is host byte order) */
+ ip4_addr_t end_hbo;
+ u_char proto; /* IPPROTO_TCP / IPPROTO_UDP / IPPROTO_IP ... 0 is all protocol */
+ u_short s_port_hbo; /* port range (NOTICE: this is host byte order) */
+ u_short e_port_hbo;
+};
+
+/* ipv4 netif flow control funcs */
+err_t fcipv4_netif_output(struct netif *netif, struct pbuf *p,
+ const ip4_addr_t *ipaddr);
+err_t fcipv4_netif_input(struct pbuf *p, struct netif *netif, s16_t ip_hdr_offset);
+
+/* ipv4 netif flow control remove */
+void fcipv4_rule_delif(struct fc_dev *fcdev);
+
+/* ipv4 flow control funcs */
+int fcipv4_rule_create(const char *ifname, const ip4_addr_t *start, const ip4_addr_t *end,
+ u_char proto, u_short s_port, u_short e_port, u_char enable,
+ fc_rate_t s_rate, fc_rate_t r_rate, size_t bsize);
+int fcipv4_rule_delete(const char *ifname, const ip4_addr_t *start, const ip4_addr_t *end,
+ u_char proto, u_short s_port, u_short e_port);
+int fcipv4_rule_change(const char *ifname, const ip4_addr_t *start, const ip4_addr_t *end,
+ u_char proto, u_short s_port, u_short e_port, u_char enable,
+ fc_rate_t s_rate, fc_rate_t r_rate, size_t bsize);
+int fcipv4_rule_get(const char *ifname, const ip4_addr_t *start, const ip4_addr_t *end,
+ u_char proto, u_short s_port, u_short e_port, u_char *enable,
+ fc_rate_t *s_rate, fc_rate_t *r_rate, size_t *bsize);
+int fcipv4_rule_search(const char *ifname, const ip4_addr_t *ipaddr,
+ u_char proto, u_short port, u_char *enable,
+ fc_rate_t *s_rate, fc_rate_t *r_rate, size_t *bsize);
+
+/* ipv4 flow control walk */
+void fcipv4_rule_traversal(VOIDFUNCPTR func, void *arg0, void *arg1,
+ void *arg2, void *arg3, void *arg4);
+void fcipv4_total_entry(unsigned int *cnt);
+
+#endif /* __IP4_FLOWCTL_H */
/*
- * This file NOT include in open source version.
+ * end
*/
diff --git a/SylixOS/net/lwip/flowctl/ip6_flowctl.c b/SylixOS/net/lwip/flowctl/ip6_flowctl.c
index 15a5e57..eacc97f 100644
--- a/SylixOS/net/lwip/flowctl/ip6_flowctl.c
+++ b/SylixOS/net/lwip/flowctl/ip6_flowctl.c
@@ -1,3 +1,572 @@
+/**
+ * @file
+ * net flow control
+ * as much as possible compatible with different versions of LwIP
+ * Verification using sylixos(tm) real-time operating system
+ */
+
+/*
+ * Copyright (c) 2006-2017 SylixOS Group.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ * 4. This code has been or is applying for intellectual property protection
+ * and can only be used with acoinfo software products.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * Author: Han.hui <hanhui@acoinfo.com>
+ *
+ */
+
+#define __SYLIXOS_KERNEL
+#include "SylixOS.h"
+
+#if LW_CFG_NET_FLOWCTL_EN > 0
+
+#include "net/if.h"
+#include "lwip/ip.h"
+#include "lwip/inet.h"
+#include "lwip/netif.h"
+#include "lwip/prot/udp.h"
+#include "lwip/prot/tcp.h"
+#include "net_flowctl.h"
+
+#if LWIP_IPV6
+
+/* netif flow control funcs */
+extern err_t fcnet_netif_output_ip6(struct netif *netif, struct pbuf *p,
+ const ip6_addr_t *ipaddr);
+
+/* ipv6 address cmp */
+static int fcipv6_addr_cmp (const ip6_addr_t *ipaddr1_hbo, const ip6_addr_t *ipaddr2_hbo)
+{
+ if (ipaddr1_hbo->addr[0] < ipaddr2_hbo->addr[0]) {
+ return (-1);
+ } else if (ipaddr1_hbo->addr[0] > ipaddr2_hbo->addr[0]) {
+ return (1);
+ } else {
+ if (ipaddr1_hbo->addr[1] < ipaddr2_hbo->addr[1]) {
+ return (-1);
+ } else if (ipaddr1_hbo->addr[1] > ipaddr2_hbo->addr[1]) {
+ return (1);
+ } else {
+ if (ipaddr1_hbo->addr[2] < ipaddr2_hbo->addr[2]) {
+ return (-1);
+ } else if (ipaddr1_hbo->addr[2] > ipaddr2_hbo->addr[2]) {
+ return (1);
+ } else {
+ if (ipaddr1_hbo->addr[3] < ipaddr2_hbo->addr[3]) {
+ return (-1);
+ } else if (ipaddr1_hbo->addr[3] > ipaddr2_hbo->addr[3]) {
+ return (1);
+ } else {
+ return (0);
+ }
+ }
+ }
+ }
+}
+
+/* ipv6 flow control match */
+static struct fc_blk *fcipv6_match (struct fc_dev *fcdev, struct pbuf *p, int send, s16_t ip_hdr_offset)
+{
+ u8_t *hdr;
+ int hlen, nexth;
+ u16_t ip6hdr_len;
+ u8_t proto;
+ struct ip6_hdr *ip6hdr;
+ struct tcp_hdr *tcphdr;
+ struct udp_hdr *udphdr;
+ struct fc_ipv6 *fcipv6;
+ ip6_addr_t ip6addr_hbo;
+ u16_t port_hbo;
+ PLW_LIST_LINE pline;
+
+ ip6hdr = (struct ip6_hdr *)((char *)p->payload + ip_hdr_offset);
+ if (p->len < (ip_hdr_offset + IP6_HLEN)) {
+ return (NULL);
+ }
+
+ if (send) {
+ fcipv6_addr_ntoh(&ip6addr_hbo, &ip6hdr->dest);
+
+ } else {
+ fcipv6_addr_ntoh(&ip6addr_hbo, &ip6hdr->src);
+ }
+
+ ip6hdr_len = IP6_HLEN;
+ hdr = (u8_t *)ip6hdr + IP6_HLEN;
+ nexth = IP6H_NEXTH(ip6hdr);
+
+ while (nexth != IP6_NEXTH_NONE) {
+ if (p->len < (ip_hdr_offset + ip6hdr_len)) {
+ return (NULL);
+ }
+ switch (nexth) {
+
+ case IP6_NEXTH_HOPBYHOP:
+ case IP6_NEXTH_DESTOPTS:
+ case IP6_NEXTH_ROUTING:
+ nexth = *hdr;
+ hlen = 8 * (1 + *(hdr + 1));
+ ip6hdr_len += hlen;
+ hdr += hlen;
+ break;
+
+ case IP6_NEXTH_FRAGMENT:
+ nexth = *hdr;
+ hlen = 8;
+ ip6hdr_len += hlen;
+ hdr += hlen;
+ break;
+
+ default:
+ goto __out;
+ break;
+ }
+ }
+
+__out:
+ proto = nexth;
+ switch (proto) {
+
+ case IP_PROTO_UDP:
+ case IP_PROTO_UDPLITE:
+ proto = IP_PROTO_UDP;
+ udphdr = (struct udp_hdr *)((char *)p->payload + ip_hdr_offset + ip6hdr_len);
+ if (p->len < (ip_hdr_offset + ip6hdr_len + UDP_HLEN)) {
+ return (NULL);
+ }
+ port_hbo = (send) ? PP_NTOHS(udphdr->src) : PP_NTOHS(udphdr->dest);
+ break;
+
+ case IP_PROTO_TCP:
+ tcphdr = (struct tcp_hdr *)((char *)p->payload + ip_hdr_offset + ip6hdr_len);
+ if (p->len < (ip_hdr_offset + ip6hdr_len + TCP_HLEN)) {
+ return (NULL);
+ }
+ port_hbo = (send) ? PP_NTOHS(tcphdr->src) : PP_NTOHS(tcphdr->dest);
+ break;
+
+ default:
+ proto = 0;
+ port_hbo = 0;
+ break;
+ }
+
+ for (pline = fcdev->fcd_list[FC_TYPE_IPV6];
+ pline != NULL;
+ pline = _list_line_get_next(pline)) {
+ fcipv6 = _LIST_ENTRY(pline, struct fc_ipv6, list);
+ if (!fcipv6->enable) {
+ continue;
+ }
+ if ((fcipv6_addr_cmp(&ip6addr_hbo, &fcipv6->start_hbo) >= 0) &&
+ (fcipv6_addr_cmp(&ip6addr_hbo, &fcipv6->end_hbo) <= 0)) {
+ if (fcipv6->proto == 0) {
+ return (&fcipv6->fcblk);
+
+ } else if (fcipv6->proto == proto) {
+ if ((proto == IP_PROTO_UDP) || (proto == IP_PROTO_TCP)) {
+ if ((port_hbo >= fcipv6->s_port_hbo) && (port_hbo <= fcipv6->e_port_hbo)) {
+ return (&fcipv6->fcblk);
+ }
+
+ } else {
+ return (&fcipv6->fcblk);
+ }
+ }
+ }
+ }
+
+ return (NULL);
+}
+
+/* ipv6 flow control send */
+static void fcipv6_netif_send (void *priv, struct pbuf *p, ip_addr_t *addr)
+{
+ struct fc_dev *fcdev = (struct fc_dev *)priv;
+
+ fcnet_netif_output_ip6(fcdev->netif, p, ip_2_ip6(addr)); /* send to fcnet layer */
+}
+
+/* ipv6 flow control recv */
+static void fcipv6_netif_recv (void *priv, struct pbuf *p)
+{
+ struct fc_dev *fcdev = (struct fc_dev *)priv;
+
+ if (fcnet_netif_tcpip_input(fcdev, p, fcdev->netif)) {
+ pbuf_free(p);
+ }
+}
+
+/* ipv6 netif flow control output */
+err_t fcipv6_netif_output (struct netif *netif, struct pbuf *p,
+ const ip6_addr_t *ipaddr)
+{
+ struct fc_dev *fcdev = NETIF_FCDEV(netif);
+ struct fc_blk *fcblk;
+
+ fcblk = fcipv6_match(fcdev, p, 1, 0);
+ if (fcblk) {
+ return (fcblk_output_ip6(fcblk, p, fcdev, ipaddr)); /* output flow control output queue */
+
+ } else {
+ return (fcnet_netif_output_ip6(netif, p, ipaddr)); /* send to fcnet layer */
+ }
+}
+
+/* ipv6 flow control input */
+err_t fcipv6_netif_input (struct pbuf *p, struct netif *netif, s16_t ip_hdr_offset)
+{
+ struct fc_dev *fcdev = NETIF_FCDEV(netif);
+ struct fc_blk *fcblk;
+
+ fcblk = fcipv6_match(fcdev, p, 0, ip_hdr_offset);
+ if (fcblk) {
+ return (fcblk_input(fcblk, p, fcdev)); /* input flow control input queue */
+
+ } else {
+ return (fcnet_netif_tcpip_input(fcdev, p, netif));
+ }
+}
+
+/* ipv6 flow control create */
+int fcipv6_rule_create (const char *ifname, const ip6_addr_t *start, const ip6_addr_t *end,
+ u_char proto, u_short s_port, u_short e_port, u_char enable,
+ fc_rate_t s_rate, fc_rate_t r_rate, size_t bsize)
+{
+ static const struct fc_funcs fcipv6_funcs = {
+ fcipv6_netif_send,
+ fcipv6_netif_recv
+ };
+
+ struct fc_dev *fcdev;
+ struct fc_ipv6 *fcipv6;
+
+ fcdev = fcnet_netif_searh(ifname);
+ if (fcdev == NULL) {
+ return (-1);
+ }
+
+ fcipv6 = (struct fc_ipv6 *)mem_malloc(sizeof(struct fc_ipv6));
+ if (fcipv6 == NULL) {
+ return (-2);
+ }
+ lib_bzero(fcipv6, sizeof(struct fc_ipv6));
+
+ fcipv6->enable = enable;
+ fcipv6_addr_ntoh(&fcipv6->start_hbo, start);
+ fcipv6_addr_ntoh(&fcipv6->end_hbo, end);
+ fcipv6->proto = proto;
+ fcipv6->s_port_hbo = PP_NTOHS(s_port);
+ fcipv6->e_port_hbo = PP_NTOHS(e_port);
+
+ fcipv6->fcblk.type = FC_TYPE_IPV6;
+ fcipv6->fcblk.s_rate = s_rate;
+ fcipv6->fcblk.r_rate = r_rate;
+ fcipv6->fcblk.buf_size = bsize;
+ fcipv6->fcblk.funcs = &fcipv6_funcs;
+
+ _List_Line_Add_Ahead(&fcipv6->list, &fcdev->fcd_list[FC_TYPE_IPV6]);
+ if (fcdev->netif) {
+ fcblk_start(&fcipv6->fcblk);
+ }
+
+ return (0);
+}
+
+/* ipv6 flow control delete */
+int fcipv6_rule_delete (const char *ifname, const ip6_addr_t *start, const ip6_addr_t *end,
+ u_char proto, u_short s_port, u_short e_port)
+{
+ struct fc_dev *fcdev;
+ struct fc_ipv6 *fcipv6;
+ PLW_LIST_LINE pline;
+ ip6_addr_t start_hbo, end_hbo;
+ u_short s_port_hbo, e_port_hbo;
+
+ fcdev = fcnet_netif_searh(ifname);
+ if (fcdev == NULL) {
+ return (-1);
+ }
+
+ fcipv6_addr_ntoh(&start_hbo, start);
+ fcipv6_addr_ntoh(&end_hbo, end);
+ s_port_hbo = PP_NTOHS(s_port);
+ e_port_hbo = PP_NTOHS(e_port);
+
+ for (pline = fcdev->fcd_list[FC_TYPE_IPV6];
+ pline != NULL;
+ pline = _list_line_get_next(pline)) {
+ fcipv6 = _LIST_ENTRY(pline, struct fc_ipv6, list);
+ if (!fcipv6_addr_cmp(&fcipv6->start_hbo, &start_hbo) &&
+ !fcipv6_addr_cmp(&fcipv6->end_hbo, &end_hbo) && (fcipv6->proto == proto) &&
+ (fcipv6->s_port_hbo == s_port_hbo) && (fcipv6->e_port_hbo == e_port_hbo)) {
+ break;
+ }
+ }
+
+ if (pline) {
+ _List_Line_Del(&fcipv6->list, &fcdev->fcd_list[FC_TYPE_IPV6]);
+ if (fcdev->netif) {
+ fcblk_stop(&fcipv6->fcblk, 0);
+ }
+ mem_free(fcipv6);
+ return (0);
+ }
+
+ return (-1);
+}
+
+/* ipv6 flow control change */
+int fcipv6_rule_change (const char *ifname, const ip6_addr_t *start, const ip6_addr_t *end,
+ u_char proto, u_short s_port, u_short e_port, u_char enable,
+ fc_rate_t s_rate, fc_rate_t r_rate, size_t bsize)
+{
+ struct fc_dev *fcdev;
+ struct fc_ipv6 *fcipv6;
+ PLW_LIST_LINE pline;
+ ip6_addr_t start_hbo, end_hbo;
+ u_short s_port_hbo, e_port_hbo;
+
+ fcdev = fcnet_netif_searh(ifname);
+ if (fcdev == NULL) {
+ return (-1);
+ }
+
+ fcipv6_addr_ntoh(&start_hbo, start);
+ fcipv6_addr_ntoh(&end_hbo, end);
+ s_port_hbo = PP_NTOHS(s_port);
+ e_port_hbo = PP_NTOHS(e_port);
+
+ for (pline = fcdev->fcd_list[FC_TYPE_IPV6];
+ pline != NULL;
+ pline = _list_line_get_next(pline)) {
+ fcipv6 = _LIST_ENTRY(pline, struct fc_ipv6, list);
+ if (!fcipv6_addr_cmp(&fcipv6->start_hbo, &start_hbo) &&
+ !fcipv6_addr_cmp(&fcipv6->end_hbo, &end_hbo) && (fcipv6->proto == proto) &&
+ (fcipv6->s_port_hbo == s_port_hbo) && (fcipv6->e_port_hbo == e_port_hbo)) {
+ break;
+ }
+ }
+
+ if (pline) {
+ fcipv6->enable = enable;
+ fcipv6->fcblk.s_rate = s_rate;
+ fcipv6->fcblk.r_rate = r_rate;
+ fcipv6->fcblk.buf_size = bsize;
+ return (0);
+ }
+
+ return (-1);
+}
+
+/* ipv6 flow control get */
+int fcipv6_rule_get (const char *ifname, const ip6_addr_t *start, const ip6_addr_t *end,
+ u_char proto, u_short s_port, u_short e_port, u_char *enable,
+ fc_rate_t *s_rate, fc_rate_t *r_rate, size_t *bsize)
+{
+ struct fc_dev *fcdev;
+ struct fc_ipv6 *fcipv6;
+ PLW_LIST_LINE pline;
+ ip6_addr_t start_hbo, end_hbo;
+ u_short s_port_hbo, e_port_hbo;
+
+ fcdev = fcnet_netif_searh(ifname);
+ if (fcdev == NULL) {
+ return (-1);
+ }
+
+ fcipv6_addr_ntoh(&start_hbo, start);
+ fcipv6_addr_ntoh(&end_hbo, end);
+ s_port_hbo = PP_NTOHS(s_port);
+ e_port_hbo = PP_NTOHS(e_port);
+
+ for (pline = fcdev->fcd_list[FC_TYPE_IPV6];
+ pline != NULL;
+ pline = _list_line_get_next(pline)) {
+ fcipv6 = _LIST_ENTRY(pline, struct fc_ipv6, list);
+ if (!fcipv6_addr_cmp(&fcipv6->start_hbo, &start_hbo) &&
+ !fcipv6_addr_cmp(&fcipv6->end_hbo, &end_hbo) && (fcipv6->proto == proto) &&
+ (fcipv6->s_port_hbo == s_port_hbo) && (fcipv6->e_port_hbo == e_port_hbo)) {
+ break;
+ }
+ }
+
+ if (pline) {
+ if (enable) {
+ *enable = fcipv6->enable;
+ }
+ if (s_rate) {
+ *s_rate = fcipv6->fcblk.s_rate;
+ }
+ if (r_rate) {
+ *r_rate = fcipv6->fcblk.r_rate;
+ }
+ if (bsize) {
+ *bsize = fcipv6->fcblk.buf_size;
+ }
+ return (0);
+ }
+
+ return (-1);
+}
+
+/* ipv6 flow control search */
+int fcipv6_rule_search (const char *ifname, const ip6_addr_t *ip6addr,
+ u_char proto, u_short port, u_char *enable,
+ fc_rate_t *s_rate, fc_rate_t *r_rate, size_t *bsize)
+{
+ struct fc_dev *fcdev;
+ struct fc_ipv6 *fcipv6;
+ PLW_LIST_LINE pline;
+ ip6_addr_t ip6addr_hbo;
+ u_short port_hbo;
+
+ fcdev = fcnet_netif_searh(ifname);
+ if (fcdev == NULL) {
+ return (-1);
+ }
+
+ fcipv6_addr_ntoh(&ip6addr_hbo, ip6addr);
+ port_hbo = PP_NTOHS(port);
+
+ for (pline = fcdev->fcd_list[FC_TYPE_IPV6];
+ pline != NULL;
+ pline = _list_line_get_next(pline)) {
+ fcipv6 = _LIST_ENTRY(pline, struct fc_ipv6, list);
+ if ((fcipv6_addr_cmp(&fcipv6->start_hbo, &ip6addr_hbo) <= 0) &&
+ (fcipv6_addr_cmp(&fcipv6->end_hbo, &ip6addr_hbo) >= 0) &&
+ (fcipv6->proto == proto) &&
+ (fcipv6->s_port_hbo <= port_hbo) && (fcipv6->e_port_hbo >= port_hbo)) {
+ break;
+ }
+ }
+
+ if (pline) {
+ if (enable) {
+ *enable = fcipv6->enable;
+ }
+ if (s_rate) {
+ *s_rate = fcipv6->fcblk.s_rate;
+ }
+ if (r_rate) {
+ *r_rate = fcipv6->fcblk.r_rate;
+ }
+ if (bsize) {
+ *bsize = fcipv6->fcblk.buf_size;
+ }
+ return (0);
+ }
+
+ return (-1);
+}
+
+/* ipv6 flow control delete */
+void fcipv6_rule_delif (struct fc_dev *fcdev)
+{
+ struct fc_ipv6 *fcipv6;
+
+ while (fcdev->fcd_list[FC_TYPE_IPV6]) {
+ fcipv6 = _LIST_ENTRY(fcdev->fcd_list[FC_TYPE_IPV6], struct fc_ipv6, list);
+ _List_Line_Del(&fcipv6->list, &fcdev->fcd_list[FC_TYPE_IPV6]);
+ if (fcdev->netif) {
+ fcblk_stop(&fcipv6->fcblk, 0);
+ }
+ mem_free(fcipv6);
+ }
+}
+
+/* ipv6 flow control walk call back */
+static void fcipv6_rule_traversal_net (struct fc_dev *fcdev,
+ VOIDFUNCPTR func, void *arg0, void *arg1,
+ void *arg2, void *arg3, void *arg4)
+{
+ struct fc_ipv6 *fcipv6;
+ PLW_LIST_LINE pline;
+
+ for (pline = fcdev->fcd_list[FC_TYPE_IPV6];
+ pline != NULL;
+ pline = _list_line_get_next(pline)) {
+ fcipv6 = _LIST_ENTRY(pline, struct fc_ipv6, list);
+ func(fcdev, fcipv6, arg0, arg1, arg2, arg3, arg4);
+ }
+}
+
+/* ipv6 flow control walk */
+void fcipv6_rule_traversal (VOIDFUNCPTR func, void *arg0, void *arg1,
+ void *arg2, void *arg3, void *arg4)
+{
+ fcnet_rule_traversal(fcipv6_rule_traversal_net, (void *)func, arg0, arg1, arg2, arg3, arg4);
+}
+
+/* ipv6 flow control cnt */
+static void fcipv6_counter (struct fc_dev *fcdev, struct fc_ipv6 *fcipv6, int *cnt)
+{
+ (*cnt) += 1;
+}
+
+/* ipv6 flow control total num */
+void fcipv6_total_entry (unsigned int *cnt)
+{
+ int count = 0;
+
+ fcipv6_rule_traversal(fcipv6_counter, &count, NULL, NULL, NULL, NULL);
+ if (cnt) {
+ *cnt = count;
+ }
+}
+
+/* ipv6 flow control netif attach */
+void fcipv6_netif_attach (struct fc_dev *fcdev)
+{
+ struct fc_ipv6 *fcipv6;
+ PLW_LIST_LINE pline;
+
+ for (pline = fcdev->fcd_list[FC_TYPE_IPV6];
+ pline != NULL;
+ pline = _list_line_get_next(pline)) {
+ fcipv6 = _LIST_ENTRY(pline, struct fc_ipv6, list);
+ fcblk_start(&fcipv6->fcblk);
+ }
+}
+
+/* ipv6 flow control netif detach */
+void fcipv6_netif_detach (struct fc_dev *fcdev)
+{
+ struct fc_ipv6 *fcipv6;
+ PLW_LIST_LINE pline;
+
+ for (pline = fcdev->fcd_list[FC_TYPE_IPV6];
+ pline != NULL;
+ pline = _list_line_get_next(pline)) {
+ fcipv6 = _LIST_ENTRY(pline, struct fc_ipv6, list);
+ fcblk_stop(&fcipv6->fcblk, 1);
+ }
+}
+
+#endif /* LWIP_IPV6 */
+#endif /* LW_CFG_NET_FLOWCTL_EN > 0 */
/*
- * This file NOT include in open source version.
+ * end
*/
diff --git a/SylixOS/net/lwip/flowctl/ip6_flowctl.h b/SylixOS/net/lwip/flowctl/ip6_flowctl.h
index 15a5e57..569d0cf 100644
--- a/SylixOS/net/lwip/flowctl/ip6_flowctl.h
+++ b/SylixOS/net/lwip/flowctl/ip6_flowctl.h
@@ -1,3 +1,109 @@
+/**
+ * @file
+ * net flow control
+ * as much as possible compatible with different versions of LwIP
+ * Verification using sylixos(tm) real-time operating system
+ */
+
+/*
+ * Copyright (c) 2006-2017 SylixOS Group.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ * 4. This code has been or is applying for intellectual property protection
+ * and can only be used with acoinfo software products.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * Author: Han.hui <hanhui@acoinfo.com>
+ *
+ */
+
+#ifndef __IP6_FLOWCTL_H
+#define __IP6_FLOWCTL_H
+
+#include "cor_flowctl.h"
+
+#if LWIP_IPV6
+
+struct fc_dev;
+
+/* ipv6 address host net byte order convert */
+#define fcipv6_addr_hton(ipaddr1, ipaddr2) \
+ do { \
+ (ipaddr1)->addr[0] = PP_HTONL((ipaddr2)->addr[0]); \
+ (ipaddr1)->addr[1] = PP_HTONL((ipaddr2)->addr[1]); \
+ (ipaddr1)->addr[2] = PP_HTONL((ipaddr2)->addr[2]); \
+ (ipaddr1)->addr[3] = PP_HTONL((ipaddr2)->addr[3]); \
+ } while (0)
+#define fcipv6_addr_ntoh(ipaddr1, ipaddr2) fcipv6_addr_hton(ipaddr1, ipaddr2)
+
+/* flow control ipv6 */
+struct fc_ipv6 {
+ /* common member */
+ struct fc_blk fcblk;
+
+ /* ipv6 member */
+ LW_LIST_LINE list;
+
+ u_char enable;
+ ip6_addr_t start_hbo; /* ip6 range (NOTICE: this is host byte order) */
+ ip6_addr_t end_hbo;
+
+ u_char proto; /* IPPROTO_TCP / IPPROTO_UDP / IPPROTO_IPV6 */
+ u_short s_port_hbo; /* port range (NOTICE: this is host byte order) */
+ u_short e_port_hbo;
+};
+
+/* ipv6 netif flow control funcs */
+err_t fcipv6_netif_output(struct netif *netif, struct pbuf *p,
+ const ip6_addr_t *ipaddr);
+err_t fcipv6_netif_input(struct pbuf *p, struct netif *netif, s16_t ip_hdr_offset);
+
+/* ipv6 netif flow control remove */
+void fcipv6_rule_delif(struct fc_dev *fcdev);
+
+/* ipv6 flow control funcs */
+int fcipv6_rule_create(const char *ifname, const ip6_addr_t *start, const ip6_addr_t *end,
+ u_char proto, u_short s_port, u_short e_port, u_char enable,
+ fc_rate_t s_rate, fc_rate_t r_rate, size_t bsize);
+int fcipv6_rule_delete(const char *ifname, const ip6_addr_t *start, const ip6_addr_t *end,
+ u_char proto, u_short s_port, u_short e_port);
+int fcipv6_rule_change(const char *ifname, const ip6_addr_t *start, const ip6_addr_t *end,
+ u_char proto, u_short s_port, u_short e_port, u_char enable,
+ fc_rate_t s_rate, fc_rate_t r_rate, size_t bsize);
+int fcipv6_rule_get(const char *ifname, const ip6_addr_t *start, const ip6_addr_t *end,
+ u_char proto, u_short s_port, u_short e_port, u_char *enable,
+ fc_rate_t *s_rate, fc_rate_t *r_rate, size_t *bsize);
+int fcipv6_rule_search(const char *ifname, const ip6_addr_t *ip6addr,
+ u_char proto, u_short port, u_char *enable,
+ fc_rate_t *s_rate, fc_rate_t *r_rate, size_t *bsize);
+
+/* ipv6 flow control walk */
+void fcipv6_rule_traversal(VOIDFUNCPTR func, void *arg0, void *arg1,
+ void *arg2, void *arg3, void *arg4);
+void fcipv6_total_entry(unsigned int *cnt);
+
+#endif /* LWIP_IPV6 */
+#endif /* __IP6_FLOWCTL_H */
/*
- * This file NOT include in open source version.
+ * end
*/
diff --git a/SylixOS/net/lwip/flowctl/net_flowctl.c b/SylixOS/net/lwip/flowctl/net_flowctl.c
index c663713..b810ff5 100644
--- a/SylixOS/net/lwip/flowctl/net_flowctl.c
+++ b/SylixOS/net/lwip/flowctl/net_flowctl.c
@@ -1,18 +1,449 @@
+/**
+ * @file
+ * net flow control
+ * as much as possible compatible with different versions of LwIP
+ * Verification using sylixos(tm) real-time operating system
+ */
+
/*
- * This file NOT include in open source version.
+ * Copyright (c) 2006-2017 SylixOS Group.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ * 4. This code has been or is applying for intellectual property protection
+ * and can only be used with acoinfo software products.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * Author: Han.hui <hanhui@acoinfo.com>
+ *
*/
-#include <lwip/netif.h>
- /*
- * fcnet_netif_attach
- */
+#define __SYLIXOS_KERNEL
+#include "SylixOS.h"
+
+#if LW_CFG_NET_FLOWCTL_EN > 0
+
+#include "net/if.h"
+#include "lwip/pbuf.h"
+#include "lwip/mem.h"
+#include "lwip/netif.h"
+#include "lwip/etharp.h"
+#include "lwip/prot/ip.h"
+#include "net_flowctl.h"
+
+/* ipv4 flow control netif hook funcs */
+extern void fcipv4_netif_attach(struct fc_dev *fcdev);
+extern void fcipv4_netif_detach(struct fc_dev *fcdev);
+
+#if LWIP_IPV6
+extern void fcipv6_netif_attach(struct fc_dev *fcdev);
+extern void fcipv6_netif_detach(struct fc_dev *fcdev);
+#endif
+
+/* netif flow control netif table */
+static LW_LIST_LINE_HEADER fcdev_list;
+
+/* netif flow control packet recv */
+static err_t fcnet_netif_recv_e (struct fc_dev *fcdev, struct pbuf *p)
+{
+ struct netif *netif = fcdev->netif;
+
+ if (fcdev->fcd_list[FC_TYPE_IPV4] || fcdev->fcd_list[FC_TYPE_IPV6]) {
+ s16_t ip_hdr_offset;
+
+ if (netif->flags & (NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET)) {
+ struct eth_hdr *ethhdr;
+ u16_t type;
+
+ ip_hdr_offset = SIZEOF_ETH_HDR;
+ ethhdr = (struct eth_hdr *)p->payload;
+ type = ethhdr->type;
+
+ if (type == PP_HTONS(ETHTYPE_VLAN)) {
+ struct eth_vlan_hdr *vlan = (struct eth_vlan_hdr*)(((char*)ethhdr) + SIZEOF_ETH_HDR);
+
+ type = vlan->tpid;
+ ip_hdr_offset += SIZEOF_VLAN_HDR;
+ }
+
+ if (p->len < ip_hdr_offset) {
+ return (ERR_BUF);
+ }
+
+ if ((type == PP_HTONS(ETHTYPE_IP)) && fcdev->fcd_list[FC_TYPE_IPV4]) {
+ return (fcipv4_netif_input(p, netif, ip_hdr_offset));
+
+#if LWIP_IPV6
+ } else if ((type == PP_HTONS(ETHTYPE_IPV6)) && fcdev->fcd_list[FC_TYPE_IPV6]) {
+ return (fcipv6_netif_input(p, netif, ip_hdr_offset));
+#endif
+ }
+
+ } else {
+ if ((IP_HDR_GET_VERSION(p->payload) == 4) && fcdev->fcd_list[FC_TYPE_IPV4]) {
+ return (fcipv4_netif_input(p, netif, 0));
+
+#if LWIP_IPV6
+ } else if ((IP_HDR_GET_VERSION(p->payload) == 6) && fcdev->fcd_list[FC_TYPE_IPV6]) {
+ return (fcipv6_netif_input(p, netif, 0));
+#endif
+ }
+ }
+ }
+
+ return (fcnet_netif_tcpip_input(fcdev, p, netif));
+}
+
+/* netif flow control packet send */
+static err_t fcnet_netif_send_e (struct fc_dev *fcdev, struct pbuf *p, ip_addr_t *addr)
+{
+#if LWIP_IPV6
+ if (IP_GET_TYPE(addr) == IPADDR_TYPE_V6) {
+ return (fcdev->o_output_ip6(fcdev->netif, p, ip_2_ip6(addr)));
+ } else
+#endif
+ {
+ return (fcdev->o_output(fcdev->netif, p, ip_2_ip4(addr)));
+ }
+}
+
+/* flow control tcpip input
+ * called in fc locking state,
+ * so we must unlock fc then call input function */
+err_t fcnet_netif_tcpip_input (struct fc_dev *fcdev, struct pbuf *p, struct netif *netif)
+{
+ /* NOTICE: o_input always tcpip_input() it only send a mbox so there is no deadlock possible */
+ return (fcdev->o_input(p, netif));
+}
+
+/* flow control input
+ * called in fc locking state */
+static err_t fcnet_netif_flowctl_input (struct pbuf *p, struct netif *netif)
+{
+ struct fc_dev *fcdev = NETIF_FCDEV(netif);
+ err_t err;
+
+ if (fcdev->fcnetif.enable) {
+ err = fcblk_input(&fcdev->fcnetif.fcblk, p, fcdev); /* input flow control input queue */
+
+ } else {
+ err = fcnet_netif_recv_e(fcdev, p); /* directly input */
+ }
+
+ if (err) {
+ pbuf_free(p);
+ }
+
+ return (ERR_OK);
+}
+
+/* flow control call back recv */
+static void fcnet_netif_recv (void *priv, struct pbuf *p)
+{
+ struct fc_dev *fcdev = (struct fc_dev *)priv;
+
+ if (fcnet_netif_recv_e(fcdev, p)) {
+ pbuf_free(0);
+ }
+}
+
+/* flow control call back send */
+static void fcnet_netif_send (void *priv, struct pbuf *p, ip_addr_t *addr)
+{
+ fcnet_netif_send_e((struct fc_dev *)priv, p, addr);
+}
+
+/* flow control input
+ * called by netdev driver
+ * use flow control thread input */
+static err_t fcnet_netif_input (struct pbuf *p, struct netif *netif)
+{
+ return (fcblk_inpkt(p, netif, fcnet_netif_flowctl_input));
+}
+
+/* flow control output
+ * called by tcpip stack */
+err_t fcnet_netif_output (struct netif *netif, struct pbuf *p,
+ const ip4_addr_t *ipaddr)
+{
+ struct fc_dev *fcdev = NETIF_FCDEV(netif);
+
+ if (fcdev->fcnetif.enable) {
+ return (fcblk_output(&fcdev->fcnetif.fcblk, p, fcdev, ipaddr)); /* output flow control output queue */
+
+ } else {
+ return (fcdev->o_output(fcdev->netif, p, ipaddr)); /* directly output */
+ }
+}
+
+#if LWIP_IPV6
+/* flow control output_ip6
+ * called by tcpip stack */
+err_t fcnet_netif_output_ip6 (struct netif *netif, struct pbuf *p,
+ const ip6_addr_t *ipaddr)
+{
+ struct fc_dev *fcdev = NETIF_FCDEV(netif);
+
+ if (fcdev->fcnetif.enable) {
+ return (fcblk_output_ip6(&fcdev->fcnetif.fcblk, p, fcdev, ipaddr)); /* output flow control output queue */
+
+ } else {
+ return (fcdev->o_output_ip6(fcdev->netif, p, ipaddr)); /* directly output */
+ }
+}
+#endif /* LWIP_IPV6 */
+
+/* flow control attach to netif no lock */
+static void fcnet_netif_attach_nolock (struct netif *netif)
+{
+ static const struct fc_funcs fcnet_funcs = {
+ fcnet_netif_send,
+ fcnet_netif_recv
+ };
+
+ struct fc_dev *fcdev;
+ char ifname[IF_NAMESIZE];
+ PLW_LIST_LINE pline;
+
+ netif_get_name(netif, ifname);
+
+ for (pline = fcdev_list; pline != NULL; pline = _list_line_get_next(pline)) {
+ fcdev = (struct fc_dev *)pline;
+ if (!fcdev->netif && !lib_strcmp(fcdev->ifname, ifname)) {
+ fcdev->o_input = netif->input;
+ fcdev->o_output = netif->output;
+#if LWIP_IPV6
+ fcdev->o_output_ip6 = netif->output_ip6;
+#endif
+ netif->input = fcnet_netif_input;
+ netif->output = fcipv4_netif_output;
+#if LWIP_IPV6
+ netif->output_ip6 = fcipv6_netif_output;
+#endif
+ NETIF_FCDEV_SET(netif, fcdev);
+ fcdev->netif = netif;
+ fcdev->fcnetif.fcblk.funcs = &fcnet_funcs;
+
+ fcblk_start(&fcdev->fcnetif.fcblk);
+ fcipv4_netif_attach(fcdev);
+#if LWIP_IPV6
+ fcipv6_netif_attach(fcdev);
+#endif
+ break;
+ }
+ }
+}
+
+/* flow control attach to netif (call back function) */
void fcnet_netif_attach (struct netif *netif)
{
+ FC_LOCK();
+ fcnet_netif_attach_nolock(netif);
+ FC_UNLOCK();
}
+/* flow control detach from netif (call back function) */
+static void fcnet_netif_detach_nolock (struct netif *netif)
+{
+ struct fc_dev *fcdev = NETIF_FCDEV(netif);
+
+ if (fcdev) {
+ netif->input = fcdev->o_input;
+ netif->output = fcdev->o_output;
+#if LWIP_IPV6
+ netif->output_ip6 = fcdev->o_output_ip6;
+#endif
+ NETIF_FCDEV_SET(netif, NULL);
+ fcdev->netif = NULL;
+
+ fcipv4_netif_detach(fcdev);
+#if LWIP_IPV6
+ fcipv6_netif_detach(fcdev);
+#endif
+ fcblk_stop(&fcdev->fcnetif.fcblk, 1);
+ }
+}
+
+/* flow control detach from netif (call back function) */
void fcnet_netif_detach (struct netif *netif)
{
+ FC_LOCK();
+ fcnet_netif_detach_nolock(netif);
+ FC_UNLOCK();
+}
+
+/* netif flow control enable */
+int fcnet_netif_add (const char *ifname)
+{
+ struct fc_dev *fcdev;
+ struct netif *netif;
+
+ netif = netif_find(ifname);
+ if (netif && NETIF_FCDEV(netif)) {
+ return (0); /* already have flow control */
+ }
+
+ fcdev = (struct fc_dev *)mem_malloc(sizeof(struct fc_dev));
+ if (fcdev == NULL) {
+ return (-1);
+ }
+ lib_bzero(fcdev, sizeof(struct fc_dev));
+
+ fcdev->fcnetif.fcblk.type = FC_TYPE_NETIF;
+ lib_strlcpy(fcdev->ifname, ifname, IF_NAMESIZE);
+
+ _List_Line_Add_Ahead(&fcdev->list, &fcdev_list);
+ if (netif) {
+ fcnet_netif_attach_nolock(netif);
+ }
+
+ return (0);
+}
+
+/* netif flow control disable */
+int fcnet_netif_delete (const char *ifname)
+{
+ struct fc_dev *fcdev;
+ struct netif *netif;
+ PLW_LIST_LINE pline;
+
+ for (pline = fcdev_list; pline != NULL; pline = _list_line_get_next(pline)) {
+ fcdev = (struct fc_dev *)pline;
+ if (!lib_strcmp(fcdev->ifname, ifname)) {
+ break;
+ }
+ }
+
+ if (pline != NULL) {
+ fcipv4_rule_delif(fcdev);
+#if LWIP_IPV6
+ fcipv6_rule_delif(fcdev);
+#endif
+ _List_Line_Del(&fcdev->list, &fcdev_list);
+
+ netif = fcdev->netif;
+ if (netif) {
+ fcnet_netif_detach_nolock(netif);
+ }
+ mem_free(fcdev);
+ return (0);
+ }
+
+ return (-1);
}
+
+/* netif flow control enable */
+struct fc_dev *fcnet_netif_searh (const char *ifname)
+{
+ struct fc_dev *fcdev;
+ PLW_LIST_LINE pline;
+
+ for (pline = fcdev_list; pline != NULL; pline = _list_line_get_next(pline)) {
+ fcdev = (struct fc_dev *)pline;
+ if (!lib_strcmp(fcdev->ifname, ifname)) {
+ break;
+ }
+ }
+
+ if (pline != NULL) {
+ return (fcdev);
+ }
+
+ return (NULL);
+}
+
+/* netif flow control set parameter */
+int fcnet_netif_set (const char *ifname, u_char enable, fc_rate_t s_rate, fc_rate_t r_rate, size_t bsize)
+{
+ struct fc_dev *fcdev = fcnet_netif_searh(ifname);
+
+ if (fcdev == NULL) {
+ return (-1);
+ }
+
+ fcdev->fcnetif.enable = enable;
+ fcdev->fcnetif.fcblk.s_rate = s_rate;
+ fcdev->fcnetif.fcblk.r_rate = r_rate;
+ fcdev->fcnetif.fcblk.buf_size = bsize;
+
+ return (0);
+}
+
+/* netif flow control get parameter */
+int fcnet_netif_get (const char *ifname, u_char *enable, fc_rate_t *s_rate, fc_rate_t *r_rate, size_t *bsize)
+{
+ struct fc_dev *fcdev = fcnet_netif_searh(ifname);
+
+ if (fcdev == NULL) {
+ return (-1);
+ }
+
+ if (enable) {
+ *enable = fcdev->fcnetif.enable;
+ }
+ if (s_rate) {
+ *s_rate = fcdev->fcnetif.fcblk.s_rate;
+ }
+ if (r_rate) {
+ *r_rate = fcdev->fcnetif.fcblk.r_rate;
+ }
+ if (bsize) {
+ *bsize = fcdev->fcnetif.fcblk.buf_size;
+ }
+
+ return (0);
+}
+
+/* netif flow control walk */
+void fcnet_rule_traversal (VOIDFUNCPTR func, void *arg0, void *arg1,
+ void *arg2, void *arg3, void *arg4, void *arg5)
+{
+ struct fc_dev *fcdev;
+ PLW_LIST_LINE pline;
+
+ for (pline = fcdev_list; pline != NULL; pline = _list_line_get_next(pline)) {
+ fcdev = (struct fc_dev *)pline;
+ func(fcdev, arg0, arg1, arg2, arg3, arg4, arg5);
+ }
+}
+
+/* fcnet flow control cnt */
+static void fcnet_counter (struct fc_dev *fcdev, int *cnt)
+{
+ (*cnt) += 1;
+}
+
+/* fcnet flow control total num */
+void fcnet_total_entry (unsigned int *cnt)
+{
+ int count = 0;
+
+ fcnet_rule_traversal(fcnet_counter, &count, NULL, NULL, NULL, NULL, NULL);
+ if (cnt) {
+ *cnt = count;
+ }
+}
+
+#endif /* LW_CFG_NET_FLOWCTL_EN > 0 */
/*
* end
*/
diff --git a/SylixOS/net/lwip/flowctl/net_flowctl.h b/SylixOS/net/lwip/flowctl/net_flowctl.h
index 9ea2bc6..c45a9d3 100644
--- a/SylixOS/net/lwip/flowctl/net_flowctl.h
+++ b/SylixOS/net/lwip/flowctl/net_flowctl.h
@@ -1,10 +1,94 @@
+/**
+ * @file
+ * net flow control
+ * as much as possible compatible with different versions of LwIP
+ * Verification using sylixos(tm) real-time operating system
+ */
+
/*
- * This file NOT include in open source version.
+ * Copyright (c) 2006-2017 SylixOS Group.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ * 4. This code has been or is applying for intellectual property protection
+ * and can only be used with acoinfo software products.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * Author: Han.hui <hanhui@acoinfo.com>
+ *
*/
#ifndef __NET_FLOWCTL_H
#define __NET_FLOWCTL_H
+#include "ip4_flowctl.h"
+#include "ip6_flowctl.h"
+
+/* flow control netif */
+struct fc_netif {
+ /* common member */
+ struct fc_blk fcblk;
+
+ /* netif member */
+ u_char enable;
+};
+
+/* flow control for each device */
+struct fc_dev {
+ LW_LIST_LINE list;
+ char ifname[IF_NAMESIZE];
+ struct netif *netif;
+
+ /* save old netif funcs */
+ netif_input_fn o_input;
+ netif_output_fn o_output;
+#if LWIP_IPV6
+ netif_output_ip6_fn o_output_ip6;
+#endif
+
+ /* ipv4, ipv6 flow control */
+ LW_LIST_LINE_HEADER fcd_list[FC_TYPE_MAX - 1];
+ struct fc_netif fcnetif; /* netif flow control */
+};
+
+#define NETIF_FCDEV(netif) ((struct fc_dev *)(netif)->flowctl)
+#define NETIF_FCDEV_SET(netif, fcdev) (netif->flowctl = (void *)(fcdev))
+
+/* flow control tcpip input */
+err_t fcnet_netif_tcpip_input(struct fc_dev *fcdev, struct pbuf *p, struct netif *netif);
+
+/* flow control funcs */
+int fcnet_netif_add(const char *ifname);
+int fcnet_netif_delete(const char *ifname);
+struct fc_dev *fcnet_netif_searh(const char *ifname);
+
+/* netif flow control set parameter */
+int fcnet_netif_set(const char *ifname, u_char enable, fc_rate_t s_rate, fc_rate_t r_rate, size_t bsize);
+int fcnet_netif_get(const char *ifname, u_char *enable, fc_rate_t *s_rate, fc_rate_t *r_rate, size_t *bsize);
+void fcnet_rule_traversal(VOIDFUNCPTR func, void *arg0, void *arg1,
+ void *arg2, void *arg3, void *arg4, void *arg5);
+void fcnet_total_entry(unsigned int *cnt);
+
+/* flow control netif hook funcs */
void fcnet_netif_attach(struct netif *netif);
void fcnet_netif_detach(struct netif *netif);
diff --git a/SylixOS/net/lwip/lwip_fix.c b/SylixOS/net/lwip/lwip_fix.c
index 9c5d105..9516e4c 100644
--- a/SylixOS/net/lwip/lwip_fix.c
+++ b/SylixOS/net/lwip/lwip_fix.c
@@ -149,7 +149,7 @@ void sys_assert_print (const char *msg, const char *func, const char *file, int
_PathLastName(file, &fname); /* 只显示文件名 */
- fprintf(stderr, "[NET] Assert: %s func: %s() file: %s line: %d\n", msg, func, fname, line);
+ _PrintFormat("[NET] Assert: %s func: %s() file: %s line: %d\r\n", msg, func, fname, line);
}
/*********************************************************************************************************
** 函数名称: sys_error_print
@@ -168,7 +168,7 @@ void sys_error_print (const char *msg, const char *func, const char *file, int
_PathLastName(file, &fname); /* 只显示文件名 */
- fprintf(stderr, "[NET] Error: %s func: %s() file: %s line: %d\n", msg, func, fname, line);
+ _PrintFormat("[NET] Error: %s func: %s() file: %s line: %d\r\n", msg, func, fname, line);
}
/*********************************************************************************************************
** 函数名称: lwip_platform_memcpy
@@ -209,12 +209,17 @@ LW_WEAK PVOID lwip_platform_smemcpy (PVOID pvDest, CPVOID pvSrc, size_t stCo
err_t sys_mutex_new (sys_mutex_t *pmutex)
{
SYS_ARCH_DECL_PROTECT(lev);
- LW_OBJECT_HANDLE hMutex = API_SemaphoreMCreate("net_mutex", LW_PRIO_DEF_CEILING,
- LW_OPTION_WAIT_PRIORITY |
- LW_OPTION_INHERIT_PRIORITY |
- LW_OPTION_DELETE_SAFE |
- LW_OPTION_OBJECT_DEBUG_UNPEND |
- LW_OPTION_OBJECT_GLOBAL, LW_NULL);
+ LW_OBJECT_HANDLE hMutex;
+ ULONG ulOpt = LW_OPTION_INHERIT_PRIORITY
+ | LW_OPTION_DELETE_SAFE
+ | LW_OPTION_OBJECT_DEBUG_UNPEND
+ | LW_OPTION_OBJECT_GLOBAL;
+
+ if (!LW_KERN_NET_LOCK_FIFO_GET()) {
+ ulOpt |= LW_OPTION_WAIT_PRIORITY;
+ }
+
+ hMutex = API_SemaphoreMCreate("net_mutex", LW_PRIO_DEF_CEILING, ulOpt, LW_NULL);
if (hMutex == LW_OBJECT_HANDLE_INVALID) {
_DebugHandle(__ERRORMESSAGE_LEVEL, "can not create net mutex.\r\n");
SYS_STATS_INC(mutex.err);
@@ -1331,7 +1336,7 @@ LW_API
uint32_t htonl (uint32_t x)
{
#if BYTE_ORDER == LITTLE_ENDIAN
- return LWIP_PLATFORM_HTONL(x);
+ return PP_HTONL(x);
#else
return x;
#endif
@@ -1349,7 +1354,7 @@ LW_API
uint32_t ntohl (uint32_t x)
{
#if BYTE_ORDER == LITTLE_ENDIAN
- return LWIP_PLATFORM_HTONL(x);
+ return PP_HTONL(x);
#else
return x;
#endif
@@ -1367,7 +1372,7 @@ LW_API
uint16_t htons (uint16_t x)
{
#if BYTE_ORDER == LITTLE_ENDIAN
- return LWIP_PLATFORM_HTONS(x);
+ return PP_HTONS(x);
#else
return x;
#endif
@@ -1385,7 +1390,7 @@ LW_API
uint16_t ntohs (uint16_t x)
{
#if BYTE_ORDER == LITTLE_ENDIAN
- return LWIP_PLATFORM_HTONS(x);
+ return PP_HTONS(x);
#else
return x;
#endif
diff --git a/SylixOS/net/lwip/lwip_fix.h b/SylixOS/net/lwip/lwip_fix.h
index 70860d7..9e31b90 100644
--- a/SylixOS/net/lwip/lwip_fix.h
+++ b/SylixOS/net/lwip/lwip_fix.h
@@ -100,7 +100,6 @@ typedef ULONG mem_ptr_t;
#define LWIP_PLATFORM_BYTESWAP 0 /* use lwip htonl() ... */
-#if BYTE_ORDER == LITTLE_ENDIAN
#ifndef __GNUC__
#ifdef __CC_ARM
#define inline __inline
@@ -109,30 +108,6 @@ typedef ULONG mem_ptr_t;
#endif /* __CC_ARM (armcc compiler) */
#endif /* __GNUC__ */
-static inline u16_t __LW_HTONS (u16_t x)
-{
- return (u16_t)((((x) & 0x00ff) << 8) |
- (((x) & 0xff00) >> 8));
-}
-static inline u32_t __LW_HTONL (u32_t x)
-{
- return (u32_t)((((x) & 0x000000ff) << 24) |
- (((x) & 0x0000ff00) << 8) |
- (((x) & 0x00ff0000) >> 8) |
- (((x) & 0xff000000) >> 24));
-}
-
-#define LWIP_PLATFORM_HTONS(x) __LW_HTONS(x)
-#define LWIP_PLATFORM_HTONL(x) __LW_HTONL(x)
-
-#define lwip_htons(x) PP_HTONS(x)
-#define lwip_htonl(x) PP_HTONL(x)
-
-#else /* BYTE_ORDER == BIG_ENDIAN */
-#define LWIP_PLATFORM_HTONS(x) x
-#define LWIP_PLATFORM_HTONL(x) x
-#endif /* BYTE_ORDER == LITTLE_ENDIAN */
-
/*********************************************************************************************************
调试输出
*********************************************************************************************************/
diff --git a/SylixOS/net/lwip/lwip_flowctl.c b/SylixOS/net/lwip/lwip_flowctl.c
index 3d5952e..e76291a 100644
--- a/SylixOS/net/lwip/lwip_flowctl.c
+++ b/SylixOS/net/lwip/lwip_flowctl.c
@@ -26,8 +26,676 @@
#if LW_CFG_NET_EN > 0 && LW_CFG_NET_FLOWCTL_EN > 0
#include "lwip/inet.h"
#include "net/flowctl.h"
+#include "flowctl/cor_flowctl.h"
+#include "flowctl/ip4_flowctl.h"
+#include "flowctl/ip6_flowctl.h"
+#include "flowctl/net_flowctl.h"
/*********************************************************************************************************
-** 函数名称: __rtIoctlInet
+ 缓冲大小
+*********************************************************************************************************/
+#define LWIP_FC_MIN_BUF_SIZE (16 * LW_CFG_KB_SIZE)
+#define LWIP_FC_MAX_BUF_SIZE (128 * LW_CFG_MB_SIZE)
+/*********************************************************************************************************
+ 速度参数
+*********************************************************************************************************/
+#define LWIP_FC_U_TO_K(rate) (rate / LW_CFG_NET_FLOWCTL_HZ)
+#define LWIP_FC_K_TO_U(rate) (rate * LW_CFG_NET_FLOWCTL_HZ)
+/*********************************************************************************************************
+** 函数名称: __fcAdd4
+** 功能描述: 添加一条 IPv4 流控指令
+** 输 入 : pfcentry 流控指令
+** 输 出 : ERROR or OK
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static INT __fcAdd4 (const struct fcentry *pfcentry)
+{
+ INT iRet;
+ ip4_addr_t ipstart, ipend;
+
+ if (pfcentry->fc_bufsize < (LWIP_FC_MIN_BUF_SIZE) ||
+ pfcentry->fc_bufsize > (LWIP_FC_MAX_BUF_SIZE)) {
+ _ErrorHandle(EINVAL);
+ return (PX_ERROR);
+ }
+
+ inet_addr_to_ip4addr(&ipstart, &((struct sockaddr_in *)&pfcentry->fc_start)->sin_addr);
+ inet_addr_to_ip4addr(&ipend, &((struct sockaddr_in *)&pfcentry->fc_end)->sin_addr);
+
+ FC_LOCK();
+ iRet = fcipv4_rule_get(pfcentry->fc_ifname, &ipstart, &ipend, pfcentry->fc_proto,
+ pfcentry->fc_sport, pfcentry->fc_eport, LW_NULL,
+ LW_NULL, LW_NULL, LW_NULL);
+ if (!iRet) {
+ FC_UNLOCK();
+ _ErrorHandle(EEXIST);
+ return (PX_ERROR);
+ }
+
+ iRet = fcnet_netif_add(pfcentry->fc_ifname); /* 网口支持流控 */
+ if (iRet < 0) {
+ FC_UNLOCK();
+ _ErrorHandle(ENOMEM);
+ return (PX_ERROR);
+ }
+
+ iRet = fcipv4_rule_create(pfcentry->fc_ifname, &ipstart, &ipend, pfcentry->fc_proto,
+ pfcentry->fc_sport, pfcentry->fc_eport, pfcentry->fc_enable,
+ LWIP_FC_U_TO_K(pfcentry->fc_downrate),
+ LWIP_FC_U_TO_K(pfcentry->fc_uprate),
+ pfcentry->fc_bufsize);
+ if (iRet < -1) {
+ FC_UNLOCK();
+ _ErrorHandle(ENOMEM);
+ return (PX_ERROR);
+
+ } else if (iRet < 0) {
+ FC_UNLOCK();
+ _ErrorHandle(EXDEV);
+ return (PX_ERROR);
+ }
+ FC_UNLOCK();
+
+ return (ERROR_NONE);
+}
+/*********************************************************************************************************
+** 函数名称: __fcAdd6
+** 功能描述: 添加一条 IPv6 流控指令
+** 输 入 : pfcentry 流控指令
+** 输 出 : ERROR or OK
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+#if LWIP_IPV6
+
+static INT __fcAdd6 (const struct fcentry *pfcentry)
+{
+ INT iRet;
+ ip6_addr_t ip6start, ip6end;
+
+ if (pfcentry->fc_bufsize < (LWIP_FC_MIN_BUF_SIZE) ||
+ pfcentry->fc_bufsize > (LWIP_FC_MAX_BUF_SIZE)) {
+ _ErrorHandle(EINVAL);
+ return (PX_ERROR);
+ }
+
+ inet6_addr_to_ip6addr(&ip6start, &((struct sockaddr_in6 *)&pfcentry->fc_start)->sin6_addr);
+ inet6_addr_to_ip6addr(&ip6end, &((struct sockaddr_in6 *)&pfcentry->fc_end)->sin6_addr);
+
+ FC_LOCK();
+ iRet = fcipv6_rule_get(pfcentry->fc_ifname, &ip6start, &ip6end, pfcentry->fc_proto,
+ pfcentry->fc_sport, pfcentry->fc_eport, LW_NULL,
+ LW_NULL, LW_NULL, LW_NULL);
+ if (!iRet) {
+ FC_UNLOCK();
+ _ErrorHandle(EEXIST);
+ return (PX_ERROR);
+ }
+
+ iRet = fcnet_netif_add(pfcentry->fc_ifname); /* 网口支持流控 */
+ if (iRet < 0) {
+ FC_UNLOCK();
+ _ErrorHandle(ENOMEM);
+ return (PX_ERROR);
+ }
+
+ iRet = fcipv6_rule_create(pfcentry->fc_ifname, &ip6start, &ip6end, pfcentry->fc_proto,
+ pfcentry->fc_sport, pfcentry->fc_eport, pfcentry->fc_enable,
+ LWIP_FC_U_TO_K(pfcentry->fc_downrate),
+ LWIP_FC_U_TO_K(pfcentry->fc_uprate),
+ pfcentry->fc_bufsize);
+ if (iRet < -1) {
+ FC_UNLOCK();
+ _ErrorHandle(ENOMEM);
+ return (PX_ERROR);
+
+ } else if (iRet < 0) {
+ FC_UNLOCK();
+ _ErrorHandle(EXDEV);
+ return (PX_ERROR);
+ }
+ FC_UNLOCK();
+
+ return (ERROR_NONE);
+}
+
+#endif
+/*********************************************************************************************************
+** 函数名称: __fcAddIf
+** 功能描述: 添加一条网络接口流控指令
+** 输 入 : pfcentry 流控指令
+** 输 出 : ERROR or OK
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static INT __fcAddIf (const struct fcentry *pfcentry)
+{
+ INT iRet;
+
+ if (pfcentry->fc_bufsize < (LWIP_FC_MIN_BUF_SIZE) ||
+ pfcentry->fc_bufsize > (LWIP_FC_MAX_BUF_SIZE)) {
+ _ErrorHandle(EINVAL);
+ return (PX_ERROR);
+ }
+
+ FC_LOCK();
+ iRet = fcnet_netif_add(pfcentry->fc_ifname); /* 网口支持流控 */
+ if (iRet < 0) {
+ FC_UNLOCK();
+ _ErrorHandle(ENOMEM);
+ return (PX_ERROR);
+ }
+
+ iRet = fcnet_netif_set(pfcentry->fc_ifname, pfcentry->fc_enable,
+ LWIP_FC_U_TO_K(pfcentry->fc_downrate),
+ LWIP_FC_U_TO_K(pfcentry->fc_uprate),
+ pfcentry->fc_bufsize);
+ if (iRet < 0) {
+ FC_UNLOCK();
+ _ErrorHandle(EXDEV);
+ return (PX_ERROR);
+ }
+ FC_UNLOCK();
+
+ return (ERROR_NONE);
+}
+/*********************************************************************************************************
+** 函数名称: __fcDel4
+** 功能描述: 删除一条 IPv4 流控指令
+** 输 入 : pfcentry 流控指令
+** 输 出 : ERROR or OK
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static INT __fcDel4 (const struct fcentry *pfcentry)
+{
+ INT iRet;
+ ip4_addr_t ipstart, ipend;
+
+ inet_addr_to_ip4addr(&ipstart, &((struct sockaddr_in *)&pfcentry->fc_start)->sin_addr);
+ inet_addr_to_ip4addr(&ipend, &((struct sockaddr_in *)&pfcentry->fc_end)->sin_addr);
+
+ FC_LOCK();
+ iRet = fcipv4_rule_delete(pfcentry->fc_ifname, &ipstart, &ipend, pfcentry->fc_proto,
+ pfcentry->fc_sport, pfcentry->fc_eport);
+ if (iRet < 0) {
+ FC_UNLOCK();
+ _ErrorHandle(ESRCH);
+ return (PX_ERROR);
+ }
+ FC_UNLOCK();
+
+ return (ERROR_NONE);
+}
+/*********************************************************************************************************
+** 函数名称: __fcDel6
+** 功能描述: 删除一条 IPv6 流控指令
+** 输 入 : pfcentry 流控指令
+** 输 出 : ERROR or OK
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+#if LWIP_IPV6
+
+static INT __fcDel6 (const struct fcentry *pfcentry)
+{
+ INT iRet;
+ ip6_addr_t ip6start, ip6end;
+
+ inet6_addr_to_ip6addr(&ip6start, &((struct sockaddr_in6 *)&pfcentry->fc_start)->sin6_addr);
+ inet6_addr_to_ip6addr(&ip6end, &((struct sockaddr_in6 *)&pfcentry->fc_end)->sin6_addr);
+
+ FC_LOCK();
+ iRet = fcipv6_rule_delete(pfcentry->fc_ifname, &ip6start, &ip6end, pfcentry->fc_proto,
+ pfcentry->fc_sport, pfcentry->fc_eport);
+ if (iRet < 0) {
+ FC_UNLOCK();
+ _ErrorHandle(ESRCH);
+ return (PX_ERROR);
+ }
+ FC_UNLOCK();
+
+ return (ERROR_NONE);
+}
+
+#endif
+/*********************************************************************************************************
+** 函数名称: __fcDelIf
+** 功能描述: 删除一条网络接口流控指令
+** 输 入 : pfcentry 流控指令
+** 输 出 : ERROR or OK
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static INT __fcDelIf (const struct fcentry *pfcentry)
+{
+ INT iRet;
+
+ FC_LOCK();
+ iRet = fcnet_netif_delete(pfcentry->fc_ifname);
+ if (iRet < 0) {
+ FC_UNLOCK();
+ _ErrorHandle(ESRCH);
+ return (PX_ERROR);
+ }
+ FC_UNLOCK();
+
+ return (ERROR_NONE);
+}
+/*********************************************************************************************************
+** 函数名称: __fcChg4
+** 功能描述: 修改一条 IPv4 流控指令
+** 输 入 : pfcentry 流控指令
+** 输 出 : ERROR or OK
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static INT __fcChg4 (const struct fcentry *pfcentry)
+{
+ INT iRet;
+ ip4_addr_t ipstart, ipend;
+
+ if (pfcentry->fc_bufsize < (LWIP_FC_MIN_BUF_SIZE) ||
+ pfcentry->fc_bufsize > (LWIP_FC_MAX_BUF_SIZE)) {
+ _ErrorHandle(EINVAL);
+ return (PX_ERROR);
+ }
+
+ inet_addr_to_ip4addr(&ipstart, &((struct sockaddr_in *)&pfcentry->fc_start)->sin_addr);
+ inet_addr_to_ip4addr(&ipend, &((struct sockaddr_in *)&pfcentry->fc_end)->sin_addr);
+
+ FC_LOCK();
+ iRet = fcipv4_rule_change(pfcentry->fc_ifname, &ipstart, &ipend, pfcentry->fc_proto,
+ pfcentry->fc_sport, pfcentry->fc_eport, pfcentry->fc_enable,
+ LWIP_FC_U_TO_K(pfcentry->fc_downrate),
+ LWIP_FC_U_TO_K(pfcentry->fc_uprate),
+ pfcentry->fc_bufsize);
+ if (iRet < 0) {
+ FC_UNLOCK();
+ _ErrorHandle(ESRCH);
+ return (PX_ERROR);
+ }
+ FC_UNLOCK();
+
+ return (ERROR_NONE);
+}
+/*********************************************************************************************************
+** 函数名称: __fcChg6
+** 功能描述: 修改一条 IPv6 流控指令
+** 输 入 : pfcentry 流控指令
+** 输 出 : ERROR or OK
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+#if LWIP_IPV6
+
+static INT __fcChg6 (const struct fcentry *pfcentry)
+{
+ INT iRet;
+ ip6_addr_t ip6start, ip6end;
+
+ if (pfcentry->fc_bufsize < (LWIP_FC_MIN_BUF_SIZE) ||
+ pfcentry->fc_bufsize > (LWIP_FC_MAX_BUF_SIZE)) {
+ _ErrorHandle(EINVAL);
+ return (PX_ERROR);
+ }
+
+ inet6_addr_to_ip6addr(&ip6start, &((struct sockaddr_in6 *)&pfcentry->fc_start)->sin6_addr);
+ inet6_addr_to_ip6addr(&ip6end, &((struct sockaddr_in6 *)&pfcentry->fc_end)->sin6_addr);
+
+ FC_LOCK();
+ iRet = fcipv6_rule_change(pfcentry->fc_ifname, &ip6start, &ip6end, pfcentry->fc_proto,
+ pfcentry->fc_sport, pfcentry->fc_eport, pfcentry->fc_enable,
+ LWIP_FC_U_TO_K(pfcentry->fc_downrate),
+ LWIP_FC_U_TO_K(pfcentry->fc_uprate),
+ pfcentry->fc_bufsize);
+ if (iRet < 0) {
+ FC_UNLOCK();
+ _ErrorHandle(ESRCH);
+ return (PX_ERROR);
+ }
+ FC_UNLOCK();
+
+ return (ERROR_NONE);
+}
+
+#endif
+/*********************************************************************************************************
+** 函数名称: __fcChgIf
+** 功能描述: 修改一条网络接口流控指令
+** 输 入 : pfcentry 流控指令
+** 输 出 : ERROR or OK
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static INT __fcChgIf (const struct fcentry *pfcentry)
+{
+ INT iRet;
+
+ if (pfcentry->fc_bufsize < (LWIP_FC_MIN_BUF_SIZE) ||
+ pfcentry->fc_bufsize > (LWIP_FC_MAX_BUF_SIZE)) {
+ _ErrorHandle(EINVAL);
+ return (PX_ERROR);
+ }
+
+ FC_LOCK();
+ iRet = fcnet_netif_set(pfcentry->fc_ifname, pfcentry->fc_enable,
+ LWIP_FC_U_TO_K(pfcentry->fc_downrate),
+ LWIP_FC_U_TO_K(pfcentry->fc_uprate),
+ pfcentry->fc_bufsize);
+ if (iRet < 0) {
+ FC_UNLOCK();
+ _ErrorHandle(ESRCH);
+ return (PX_ERROR);
+ }
+ FC_UNLOCK();
+
+ return (ERROR_NONE);
+}
+/*********************************************************************************************************
+** 函数名称: __fcGet4
+** 功能描述: 获取一条 IPv4 流控指令
+** 输 入 : pfcentry 流控指令
+** 输 出 : ERROR or OK
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static INT __fcGet4 (struct fcentry *pfcentry)
+{
+ INT iRet;
+ ip4_addr_t ipstart, ipend;
+ fc_rate_t uprate, downrate;
+
+ inet_addr_to_ip4addr(&ipstart, &((struct sockaddr_in *)&pfcentry->fc_start)->sin_addr);
+ inet_addr_to_ip4addr(&ipend, &((struct sockaddr_in *)&pfcentry->fc_end)->sin_addr);
+
+ FC_LOCK();
+ iRet = fcipv4_rule_get(pfcentry->fc_ifname, &ipstart, &ipend, pfcentry->fc_proto,
+ pfcentry->fc_sport, pfcentry->fc_eport, &pfcentry->fc_enable,
+ &downrate, &uprate, &pfcentry->fc_bufsize);
+ if (iRet < 0) {
+ FC_UNLOCK();
+ _ErrorHandle(ESRCH);
+ return (PX_ERROR);
+ }
+ FC_UNLOCK();
+
+ pfcentry->fc_uprate = LWIP_FC_K_TO_U(uprate);
+ pfcentry->fc_downrate = LWIP_FC_K_TO_U(downrate);
+
+ return (ERROR_NONE);
+}
+/*********************************************************************************************************
+** 函数名称: __fcGet6
+** 功能描述: 获取一条 IPv6 流控指令
+** 输 入 : pfcentry 流控指令
+** 输 出 : ERROR or OK
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+#if LWIP_IPV6
+
+static INT __fcGet6 (struct fcentry *pfcentry)
+{
+ INT iRet;
+ ip6_addr_t ip6start, ip6end;
+ fc_rate_t uprate, downrate;
+
+ inet6_addr_to_ip6addr(&ip6start, &((struct sockaddr_in6 *)&pfcentry->fc_start)->sin6_addr);
+ inet6_addr_to_ip6addr(&ip6end, &((struct sockaddr_in6 *)&pfcentry->fc_end)->sin6_addr);
+
+ FC_LOCK();
+ iRet = fcipv6_rule_get(pfcentry->fc_ifname, &ip6start, &ip6end, pfcentry->fc_proto,
+ pfcentry->fc_sport, pfcentry->fc_eport, &pfcentry->fc_enable,
+ &downrate, &uprate, &pfcentry->fc_bufsize);
+ if (iRet < 0) {
+ FC_UNLOCK();
+ _ErrorHandle(ESRCH);
+ return (PX_ERROR);
+ }
+ FC_UNLOCK();
+
+ pfcentry->fc_uprate = LWIP_FC_K_TO_U(uprate);
+ pfcentry->fc_downrate = LWIP_FC_K_TO_U(downrate);
+
+ return (ERROR_NONE);
+}
+
+#endif
+/*********************************************************************************************************
+** 函数名称: __fcGetIf
+** 功能描述: 获取一条网络接口流控指令
+** 输 入 : pfcentry 流控指令
+** 输 出 : ERROR or OK
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static INT __fcGetIf (struct fcentry *pfcentry)
+{
+ INT iRet;
+ fc_rate_t uprate, downrate;
+
+ FC_LOCK();
+ iRet = fcnet_netif_get(pfcentry->fc_ifname, &pfcentry->fc_enable,
+ &downrate, &uprate, &pfcentry->fc_bufsize);
+ if (iRet < 0) {
+ FC_UNLOCK();
+ _ErrorHandle(ESRCH);
+ return (PX_ERROR);
+ }
+ FC_UNLOCK();
+
+ pfcentry->fc_uprate = LWIP_FC_K_TO_U(uprate);
+ pfcentry->fc_downrate = LWIP_FC_K_TO_U(downrate);
+
+ return (ERROR_NONE);
+}
+/*********************************************************************************************************
+** 函数名称: __fcLst4Walk
+** 功能描述: 获取整个 IPv4 流控信息回调
+** 输 入 : fcdev 流控设备控制块
+** fcipv4 IPv4 流控控制块
+** pfcelist 流控信息缓存
+** 输 出 : ERROR or OK
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static void __fcLst4Walk (struct fc_dev *fcdev, struct fc_ipv4 *fcipv4, struct fcentry_list *pfcelist)
+{
+ if (pfcelist->fcl_num < pfcelist->fcl_bcnt) {
+ struct fcentry *pfcentry = &pfcelist->fcl_buf[pfcelist->fcl_num];
+ ip4_addr_t ipsaddr, ipeaddr;
+
+ ipsaddr.addr = PP_HTONL(fcipv4->start_hbo.addr);
+ ipeaddr.addr = PP_HTONL(fcipv4->end_hbo.addr);
+
+ pfcentry->fc_start.sa_len = sizeof(struct sockaddr_in);
+ pfcentry->fc_start.sa_family = AF_INET;
+ pfcentry->fc_end.sa_len = sizeof(struct sockaddr_in);
+ pfcentry->fc_end.sa_family = AF_INET;
+
+ inet_addr_from_ip4addr(&((struct sockaddr_in *)&pfcentry->fc_start)->sin_addr, &ipsaddr);
+ inet_addr_from_ip4addr(&((struct sockaddr_in *)&pfcentry->fc_end)->sin_addr, &ipeaddr);
+
+ pfcentry->fc_type = FCT_IP;
+ pfcentry->fc_enable = fcipv4->enable;
+ pfcentry->fc_proto = fcipv4->proto;
+ pfcentry->fc_sport = PP_HTONS(fcipv4->s_port_hbo);
+ pfcentry->fc_eport = PP_HTONS(fcipv4->e_port_hbo);
+
+ lib_strlcpy(pfcentry->fc_ifname, fcdev->ifname, IF_NAMESIZE);
+
+ pfcentry->fc_uprate = LWIP_FC_K_TO_U(fcipv4->fcblk.r_rate);
+ pfcentry->fc_downrate = LWIP_FC_K_TO_U(fcipv4->fcblk.s_rate);
+ pfcentry->fc_bufsize = fcipv4->fcblk.buf_size;
+ pfcelist->fcl_num++;
+ }
+}
+/*********************************************************************************************************
+** 函数名称: __fcLst4
+** 功能描述: 获取整个 IPv4 流控信息
+** 输 入 : pfcelist 流控信息缓存
+** 输 出 : ERROR or OK
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static INT __fcLst4 (struct fcentry_list *pfcelist)
+{
+ UINT uiTotal;
+
+ pfcelist->fcl_num = 0;
+
+ FC_LOCK();
+ fcipv4_total_entry(&uiTotal);
+ pfcelist->fcl_total = uiTotal;
+ if (!pfcelist->fcl_bcnt || !pfcelist->fcl_buf) {
+ FC_UNLOCK();
+ return (ERROR_NONE);
+ }
+ fcipv4_rule_traversal(__fcLst4Walk, pfcelist, LW_NULL, LW_NULL, LW_NULL, LW_NULL);
+ FC_UNLOCK();
+
+ return (ERROR_NONE);
+}
+/*********************************************************************************************************
+** 函数名称: __fcLst6Walk
+** 功能描述: 获取整个 IPv6 流控信息回调
+** 输 入 : fcdev 流控设备控制块
+** fcipv6 IPv6 流控控制块
+** pfcelist 流控信息缓存
+** 输 出 : ERROR or OK
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+#if LWIP_IPV6
+
+static void __fcLst6Walk (struct fc_dev *fcdev, struct fc_ipv6 *fcipv6, struct fcentry_list *pfcelist)
+{
+ if (pfcelist->fcl_num < pfcelist->fcl_bcnt) {
+ struct fcentry *pfcentry = &pfcelist->fcl_buf[pfcelist->fcl_num];
+ ip6_addr_t ip6saddr, ip6eaddr;
+
+ fcipv6_addr_hton(&ip6saddr, &fcipv6->start_hbo);
+ fcipv6_addr_hton(&ip6eaddr, &fcipv6->end_hbo);
+
+ pfcentry->fc_start.sa_len = sizeof(struct sockaddr_in6);
+ pfcentry->fc_start.sa_family = AF_INET6;
+ pfcentry->fc_end.sa_len = sizeof(struct sockaddr_in6);
+ pfcentry->fc_end.sa_family = AF_INET6;
+
+ inet6_addr_from_ip6addr(&((struct sockaddr_in6 *)&pfcentry->fc_start)->sin6_addr, &ip6saddr);
+ inet6_addr_from_ip6addr(&((struct sockaddr_in6 *)&pfcentry->fc_end)->sin6_addr, &ip6eaddr);
+
+ pfcentry->fc_type = FCT_IP;
+ pfcentry->fc_enable = fcipv6->enable;
+ pfcentry->fc_proto = fcipv6->proto;
+ pfcentry->fc_sport = PP_HTONS(fcipv6->s_port_hbo);
+ pfcentry->fc_eport = PP_HTONS(fcipv6->e_port_hbo);
+
+ lib_strlcpy(pfcentry->fc_ifname, fcdev->ifname, IF_NAMESIZE);
+
+ pfcentry->fc_uprate = LWIP_FC_K_TO_U(fcipv6->fcblk.r_rate);
+ pfcentry->fc_downrate = LWIP_FC_K_TO_U(fcipv6->fcblk.s_rate);
+ pfcentry->fc_bufsize = fcipv6->fcblk.buf_size;
+ pfcelist->fcl_num++;
+ }
+}
+/*********************************************************************************************************
+** 函数名称: __fcLst6
+** 功能描述: 获取整个 IPv6 流控信息
+** 输 入 : pfcelist 流控信息缓存
+** 输 出 : ERROR or OK
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static INT __fcLst6 (struct fcentry_list *pfcelist)
+{
+ UINT uiTotal;
+
+ pfcelist->fcl_num = 0;
+
+ FC_LOCK();
+ fcipv6_total_entry(&uiTotal);
+ pfcelist->fcl_total = uiTotal;
+ if (!pfcelist->fcl_bcnt || !pfcelist->fcl_buf) {
+ FC_UNLOCK();
+ return (ERROR_NONE);
+ }
+ fcipv6_rule_traversal(__fcLst6Walk, pfcelist, LW_NULL, LW_NULL, LW_NULL, LW_NULL);
+ FC_UNLOCK();
+
+ return (ERROR_NONE);
+}
+
+#endif
+/*********************************************************************************************************
+** 函数名称: __fcLstIfWalk
+** 功能描述: 获取整个网络接口流控信息回调
+** 输 入 : fcdev 流控设备控制块
+** pfcelist 流控信息缓存
+** 输 出 : ERROR or OK
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static void __fcLstIfWalk (struct fc_dev *fcdev, struct fcentry_list *pfcelist)
+{
+ if (pfcelist->fcl_num < pfcelist->fcl_bcnt) {
+ struct fcentry *pfcentry = &pfcelist->fcl_buf[pfcelist->fcl_num];
+ ip4_addr_t ipsaddr, ipeaddr;
+
+ ipsaddr.addr = 0;
+ ipeaddr.addr = 0;
+
+ pfcentry->fc_start.sa_len = sizeof(struct sockaddr_in);
+ pfcentry->fc_start.sa_family = AF_INET;
+ pfcentry->fc_end.sa_len = sizeof(struct sockaddr_in);
+ pfcentry->fc_end.sa_family = AF_INET;
+
+ inet_addr_from_ip4addr(&((struct sockaddr_in *)&pfcentry->fc_start)->sin_addr, &ipsaddr);
+ inet_addr_from_ip4addr(&((struct sockaddr_in *)&pfcentry->fc_end)->sin_addr, &ipeaddr);
+
+ pfcentry->fc_type = FCT_IP;
+ pfcentry->fc_enable = fcdev->fcnetif.enable;
+ pfcentry->fc_proto = 0;
+ pfcentry->fc_sport = 0;
+ pfcentry->fc_eport = 0;
+
+ lib_strlcpy(pfcentry->fc_ifname, fcdev->ifname, IF_NAMESIZE);
+
+ pfcentry->fc_uprate = LWIP_FC_K_TO_U(fcdev->fcnetif.fcblk.r_rate);
+ pfcentry->fc_downrate = LWIP_FC_K_TO_U(fcdev->fcnetif.fcblk.s_rate);
+ pfcentry->fc_bufsize = fcdev->fcnetif.fcblk.buf_size;
+ pfcelist->fcl_num++;
+ }
+}
+/*********************************************************************************************************
+** 函数名称: __fcLstIf
+** 功能描述: 获取整个网络接口流控信息
+** 输 入 : pfcelist 流控信息缓存
+** 输 出 : ERROR or OK
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static INT __fcLstIf (struct fcentry_list *pfcelist)
+{
+ UINT uiTotal;
+
+ pfcelist->fcl_num = 0;
+
+ FC_LOCK();
+ fcnet_total_entry(&uiTotal);
+ pfcelist->fcl_total = uiTotal;
+ if (!pfcelist->fcl_bcnt || !pfcelist->fcl_buf) {
+ FC_UNLOCK();
+ return (ERROR_NONE);
+ }
+ fcnet_rule_traversal(__fcLstIfWalk, pfcelist, LW_NULL, LW_NULL, LW_NULL, LW_NULL, LW_NULL);
+ FC_UNLOCK();
+
+ return (ERROR_NONE);
+}
+/*********************************************************************************************************
+** 函数名称: __fcIoctlInet
** 功能描述: SIOCADDRT / SIOCDELRT 命令处理接口
** 输 入 : iFamily AF_INET / AF_INET6
** iCmd SIOCADDRT / SIOCDELRT
@@ -38,8 +706,97 @@
*********************************************************************************************************/
INT __fcIoctlInet (INT iFamily, INT iCmd, PVOID pvArg)
{
- _ErrorHandle(ENOSYS);
- return (PX_ERROR);
+ struct fcentry *pfcentry = (struct fcentry *)pvArg;
+ INT iRet = PX_ERROR;
+
+ if (!pfcentry) {
+ _ErrorHandle(EINVAL);
+ return (PX_ERROR);
+ }
+
+ switch (iCmd) {
+
+ case SIOCADDFC: /* 添加一条限速命令 */
+ if (pfcentry->fc_type == FCT_IP) {
+ if (iFamily == AF_INET) {
+ iRet = __fcAdd4(pfcentry);
+ }
+#if LWIP_IPV6
+ else {
+ iRet = __fcAdd6(pfcentry);
+ }
+#endif
+ } else {
+ iRet = __fcAddIf(pfcentry);
+ }
+ break;
+
+ case SIOCDELFC: /* 删除一条限速命令 */
+ if (pfcentry->fc_type == FCT_IP) {
+ if (iFamily == AF_INET) {
+ iRet = __fcDel4(pfcentry);
+ }
+#if LWIP_IPV6
+ else {
+ iRet = __fcDel6(pfcentry);
+ }
+#endif
+ } else {
+ iRet = __fcDelIf(pfcentry);
+ }
+ break;
+
+ case SIOCCHGFC: /* 改变一条限速命令 */
+ if (pfcentry->fc_type == FCT_IP) {
+ if (iFamily == AF_INET) {
+ iRet = __fcChg4(pfcentry);
+ }
+#if LWIP_IPV6
+ else {
+ iRet = __fcChg6(pfcentry);
+ }
+#endif
+ } else {
+ iRet = __fcChgIf(pfcentry);
+ }
+ break;
+
+ case SIOCGETFC: /* 获得一条限速命令 */
+ if (pfcentry->fc_type == FCT_IP) {
+ if (iFamily == AF_INET) {
+ iRet = __fcGet4(pfcentry);
+ }
+#if LWIP_IPV6
+ else {
+ iRet = __fcGet6(pfcentry);
+ }
+#endif
+ } else {
+ iRet = __fcGetIf(pfcentry);
+ }
+ break;
+
+ case SIOCLSTFC: /* 列表所有限速命令 */
+ if (pfcentry->fc_type == FCT_IP) {
+ if (iFamily == AF_INET) {
+ iRet = __fcLst4((struct fcentry_list *)pvArg);
+ }
+#if LWIP_IPV6
+ else {
+ iRet = __fcLst6((struct fcentry_list *)pvArg);
+ }
+#endif
+ } else {
+ iRet = __fcLstIf((struct fcentry_list *)pvArg);
+ }
+ break;
+
+ default:
+ _ErrorHandle(ENOSYS);
+ break;
+ }
+
+ return (iRet);
}
#endif /* LW_CFG_NET_EN > 0 */
diff --git a/SylixOS/net/lwip/lwip_flowsh.c b/SylixOS/net/lwip/lwip_flowsh.c
index 41faea5..608182a 100644
--- a/SylixOS/net/lwip/lwip_flowsh.c
+++ b/SylixOS/net/lwip/lwip_flowsh.c
@@ -27,6 +27,760 @@
#if LW_CFG_NET_EN > 0 && LW_CFG_SHELL_EN > 0 && LW_CFG_NET_FLOWCTL_EN > 0
#include "net/flowctl.h"
/*********************************************************************************************************
+ 默认缓冲
+*********************************************************************************************************/
+#define FC_DEFAULT_BUF_SIZE_KB (LW_CFG_NET_FLOWCTL_DEF_BSIZE >> 10)
+/*********************************************************************************************************
+** 函数名称: __fc_show_ipv4
+** 功能描述: 显示 IPv4 流控信息
+** 输 入 : NONE
+** 输 出 : NONE
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static VOID __fc_show_ipv4 (VOID)
+{
+ INT iRet, i;
+ INT iSock;
+ CHAR cStrSSrc[IP4ADDR_STRLEN_MAX];
+ CHAR cStrESrc[IP4ADDR_STRLEN_MAX];
+ PCHAR pcProto;
+ INT iSPort, iEPort;
+ struct fcentry_list fcentrylist;
+ struct fcentry *pfcentry;
+
+
+ fcentrylist.fcl_type = FCT_IP;
+ fcentrylist.fcl_bcnt = 0;
+ fcentrylist.fcl_num = 0;
+ fcentrylist.fcl_total = 0;
+ fcentrylist.fcl_buf = LW_NULL;
+
+ printf("IPv4 Flow Control Table:\n");
+ printf("Source(s) Source(e) Proto Port(s) Port(e) Uplink (KB/s) Downlink (KB/s) Stat Iface\n");
+
+ iSock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (iSock < 0) {
+ fprintf(stderr, "can not create socket error: %s!\n", lib_strerror(errno));
+ return;
+ }
+
+ iRet = ioctl(iSock, SIOCLSTFC, &fcentrylist);
+ if (iRet < 0) {
+ fprintf(stderr, "command 'SIOCLSTFC' error: %s!\n", lib_strerror(errno));
+ close(iSock);
+ return;
+ }
+
+ fcentrylist.fcl_buf = (struct fcentry *)__SHEAP_ALLOC(sizeof(struct fcentry) * fcentrylist.fcl_total);
+ if (!fcentrylist.fcl_buf) {
+ fprintf(stderr, "error: %s!\n", lib_strerror(errno));
+ close(iSock);
+ return;
+ }
+
+ fcentrylist.fcl_bcnt = fcentrylist.fcl_total;
+ iRet = ioctl(iSock, SIOCLSTFC, &fcentrylist);
+ if (iRet < 0) {
+ fprintf(stderr, "command 'SIOCLSTFC' error: %s!\n", lib_strerror(errno));
+ close(iSock);
+ return;
+ }
+ close(iSock);
+
+ for (i = 0; i < fcentrylist.fcl_num; i++) {
+ pfcentry = &fcentrylist.fcl_buf[i];
+ inet_ntoa_r(((struct sockaddr_in *)&pfcentry->fc_start)->sin_addr, cStrSSrc, IP4ADDR_STRLEN_MAX);
+ inet_ntoa_r(((struct sockaddr_in *)&pfcentry->fc_end)->sin_addr, cStrESrc, IP4ADDR_STRLEN_MAX);
+
+ switch (pfcentry->fc_proto) {
+
+ case 0:
+ pcProto = "all";
+ iSPort = -1;
+ iEPort = -1;
+ break;
+
+ case IPPROTO_TCP:
+ pcProto = "tcp";
+ iSPort = ntohs(pfcentry->fc_sport);
+ iEPort = ntohs(pfcentry->fc_eport);
+ break;
+
+ case IPPROTO_UDP:
+ case IPPROTO_UDPLITE:
+ pcProto = "udp";
+ iSPort = ntohs(pfcentry->fc_sport);
+ iEPort = ntohs(pfcentry->fc_eport);
+ break;
+
+ case IPPROTO_ICMP:
+ pcProto = "icmp";
+ iSPort = -1;
+ iEPort = -1;
+ break;
+
+ default:
+ pcProto = "unknown";
+ iSPort = -1;
+ iEPort = -1;
+ break;
+ }
+
+ printf("%-15s %-15s %-7s %-8d %-8d %-15qd %-15qd %-4s %s\n",
+ cStrSSrc, cStrESrc, pcProto, iSPort, iEPort,
+ pfcentry->fc_uprate >> 10,
+ pfcentry->fc_downrate >> 10,
+ pfcentry->fc_enable ? "En" : "Dis",
+ pfcentry->fc_ifname);
+ }
+
+ __SHEAP_FREE(fcentrylist.fcl_buf);
+ printf("\n");
+}
+/*********************************************************************************************************
+** 函数名称: __fc_show_ipv6
+** 功能描述: 显示 IPv6 流控信息
+** 输 入 : NONE
+** 输 出 : NONE
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+#if LWIP_IPV6
+
+static VOID __fc_show_ipv6 (VOID)
+{
+ INT iRet, i;
+ INT iSock;
+ CHAR cStrSSrc[IP6ADDR_STRLEN_MAX];
+ CHAR cStrESrc[IP6ADDR_STRLEN_MAX];
+ PCHAR pcProto;
+ INT iSPort, iEPort;
+ struct fcentry_list fcentrylist;
+ struct fcentry *pfcentry;
+
+ fcentrylist.fcl_type = FCT_IP;
+ fcentrylist.fcl_bcnt = 0;
+ fcentrylist.fcl_num = 0;
+ fcentrylist.fcl_total = 0;
+ fcentrylist.fcl_buf = LW_NULL;
+
+ printf("IPv6 Flow Control Table:\n");
+ printf("Source(s) Source(e) "
+ "Proto Port(s) Port(e) Uplink (KB/s) Downlink (KB/s) Stat Iface\n");
+
+ iSock = socket(AF_INET6, SOCK_DGRAM, 0);
+ if (iSock < 0) {
+ fprintf(stderr, "can not create socket error: %s!\n", lib_strerror(errno));
+ return;
+ }
+
+ iRet = ioctl(iSock, SIOCLSTFC, &fcentrylist);
+ if (iRet < 0) {
+ fprintf(stderr, "command 'SIOCLSTFC' error: %s!\n", lib_strerror(errno));
+ close(iSock);
+ return;
+ }
+
+ fcentrylist.fcl_buf = (struct fcentry *)__SHEAP_ALLOC(sizeof(struct fcentry) * fcentrylist.fcl_total);
+ if (!fcentrylist.fcl_buf) {
+ fprintf(stderr, "error: %s!\n", lib_strerror(errno));
+ close(iSock);
+ return;
+ }
+
+ fcentrylist.fcl_bcnt = fcentrylist.fcl_total;
+ iRet = ioctl(iSock, SIOCLSTFC, &fcentrylist);
+ if (iRet < 0) {
+ fprintf(stderr, "command 'SIOCLSTFC' error: %s!\n", lib_strerror(errno));
+ close(iSock);
+ return;
+ }
+ close(iSock);
+
+ for (i = 0; i < fcentrylist.fcl_num; i++) {
+ pfcentry = &fcentrylist.fcl_buf[i];
+ inet6_ntoa_r(((struct sockaddr_in6 *)&pfcentry->fc_start)->sin6_addr, cStrSSrc, IP6ADDR_STRLEN_MAX);
+ inet6_ntoa_r(((struct sockaddr_in6 *)&pfcentry->fc_end)->sin6_addr, cStrESrc, IP6ADDR_STRLEN_MAX);
+
+ switch (pfcentry->fc_proto) {
+
+ case 0:
+ pcProto = "all";
+ iSPort = -1;
+ iEPort = -1;
+ break;
+
+ case IPPROTO_TCP:
+ pcProto = "tcp";
+ iSPort = ntohs(pfcentry->fc_sport);
+ iEPort = ntohs(pfcentry->fc_eport);
+ break;
+
+ case IPPROTO_UDP:
+ case IPPROTO_UDPLITE:
+ pcProto = "udp";
+ iSPort = ntohs(pfcentry->fc_sport);
+ iEPort = ntohs(pfcentry->fc_eport);
+ break;
+
+ case IPPROTO_ICMP:
+ pcProto = "icmp";
+ iSPort = -1;
+ iEPort = -1;
+ break;
+
+ default:
+ pcProto = "unknown";
+ iSPort = -1;
+ iEPort = -1;
+ break;
+ }
+
+ printf("%-32s %-32s %-7s %-8d %-8d %-15qd %-15qd %-4s %s\n",
+ cStrSSrc, cStrESrc, pcProto, iSPort, iEPort,
+ pfcentry->fc_uprate >> 10,
+ pfcentry->fc_downrate >> 10,
+ pfcentry->fc_enable ? "En" : "Dis",
+ pfcentry->fc_ifname);
+ }
+
+ __SHEAP_FREE(fcentrylist.fcl_buf);
+ printf("\n");
+}
+
+#endif /* LWIP_IPV6 */
+/*********************************************************************************************************
+** 函数名称: __fc_show_if
+** 功能描述: 显示网络接口流控信息
+** 输 入 : NONE
+** 输 出 : NONE
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static VOID __fc_show_if (VOID)
+{
+ INT iRet, i;
+ INT iSock;
+ struct fcentry_list fcentrylist;
+ struct fcentry *pfcentry;
+
+ fcentrylist.fcl_type = FCT_IF;
+ fcentrylist.fcl_bcnt = 0;
+ fcentrylist.fcl_num = 0;
+ fcentrylist.fcl_total = 0;
+ fcentrylist.fcl_buf = LW_NULL;
+
+ printf("Net Interface Flow Control Table:\n");
+ printf("Uplink (KB/s) Downlink (KB/s) Stat Iface\n");
+
+ iSock = socket(AF_INET6, SOCK_DGRAM, 0);
+ if (iSock < 0) {
+ fprintf(stderr, "can not create socket error: %s!\n", lib_strerror(errno));
+ return;
+ }
+
+ iRet = ioctl(iSock, SIOCLSTFC, &fcentrylist);
+ if (iRet < 0) {
+ fprintf(stderr, "command 'SIOCLSTFC' error: %s!\n", lib_strerror(errno));
+ close(iSock);
+ return;
+ }
+
+ fcentrylist.fcl_buf = (struct fcentry *)__SHEAP_ALLOC(sizeof(struct fcentry) * fcentrylist.fcl_total);
+ if (!fcentrylist.fcl_buf) {
+ fprintf(stderr, "error: %s!\n", lib_strerror(errno));
+ close(iSock);
+ return;
+ }
+
+ fcentrylist.fcl_bcnt = fcentrylist.fcl_total;
+ iRet = ioctl(iSock, SIOCLSTFC, &fcentrylist);
+ if (iRet < 0) {
+ fprintf(stderr, "command 'SIOCLSTFC' error: %s!\n", lib_strerror(errno));
+ close(iSock);
+ return;
+ }
+ close(iSock);
+
+ for (i = 0; i < fcentrylist.fcl_num; i++) {
+ pfcentry = &fcentrylist.fcl_buf[i];
+ printf("%-15qd %-15qd %-4s %s\n",
+ pfcentry->fc_uprate >> 10,
+ pfcentry->fc_downrate >> 10,
+ pfcentry->fc_enable ? "En" : "Dis",
+ pfcentry->fc_ifname);
+ }
+
+ __SHEAP_FREE(fcentrylist.fcl_buf);
+ printf("\n");
+}
+/*********************************************************************************************************
+** 函数名称: __fc_add_if
+** 功能描述: 添加网络接口流控信息
+** 输 入 : iArgC 参数个数
+** ppcArgV 参数表
+** 输 出 : ERROR
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static INT __fc_add_if (INT iArgC, PCHAR *ppcArgV)
+{
+ INT iRet;
+ INT iSock;
+ struct fcentry fcentry;
+ size_t stBufSize = FC_DEFAULT_BUF_SIZE_KB;
+
+ lib_bzero(&fcentry, sizeof(struct fcentry));
+ fcentry.fc_type = FCT_IF;
+ fcentry.fc_enable = 1;
+
+ if ((iArgC < 7) || lib_strcmp(ppcArgV[3], "dev")) {
+__arg_error:
+ fprintf(stderr, "arguments error!\n");
+ return (-ERROR_TSHELL_EPARAM);
+ }
+
+ lib_strlcpy(fcentry.fc_ifname, ppcArgV[4], IF_NAMESIZE);
+
+ if (sscanf(ppcArgV[5], "%qu", &fcentry.fc_uprate) != 1) {
+ goto __arg_error;
+ }
+
+ if (sscanf(ppcArgV[6], "%qu", &fcentry.fc_downrate) != 1) {
+ goto __arg_error;
+ }
+
+ if (iArgC > 7) {
+ if (sscanf(ppcArgV[7], "%zu", &stBufSize) != 1) {
+ goto __arg_error;
+ }
+ }
+
+ fcentry.fc_uprate <<= 10;
+ fcentry.fc_downrate <<= 10;
+ fcentry.fc_bufsize = (stBufSize << 10);
+
+ iSock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (iSock < 0) {
+ fprintf(stderr, "can not create socket error: %s!\n", lib_strerror(errno));
+ return (PX_ERROR);
+ }
+
+ iRet = ioctl(iSock, SIOCADDFC, &fcentry);
+ if (iRet < 0) {
+ fprintf(stderr, "command 'SIOCADDFC' error: %s!\n", lib_strerror(errno));
+ close(iSock);
+ return (PX_ERROR);
+ }
+ close(iSock);
+
+ return (ERROR_NONE);
+}
+/*********************************************************************************************************
+** 函数名称: __fc_add_ip
+** 功能描述: 添加 IPv4 流控信息
+** 输 入 : iArgC 参数个数
+** ppcArgV 参数表
+** 输 出 : ERROR
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static INT __fc_add_ip (INT iArgC, PCHAR *ppcArgV)
+{
+ INT iRet, iBuf, iIndex;
+ INT iSPort, iEPort;
+ INT iSock;
+ struct fcentry fcentry;
+ size_t stBufSize = FC_DEFAULT_BUF_SIZE_KB;
+
+ lib_bzero(&fcentry, sizeof(struct fcentry));
+ fcentry.fc_type = FCT_IP;
+ fcentry.fc_enable = 1;
+
+ if (iArgC < 10) {
+__arg_error:
+ fprintf(stderr, "arguments error!\n");
+ return (-ERROR_TSHELL_EPARAM);
+ }
+
+ if (!lib_strcmp(ppcArgV[5], "all")) {
+ fcentry.fc_proto = 0;
+ iBuf = 10;
+
+ } else if (!lib_strcmp(ppcArgV[5], "tcp") && (iArgC >= 12)) {
+ fcentry.fc_proto = IPPROTO_TCP;
+ iBuf = 12;
+
+ } else if (!lib_strcmp(ppcArgV[5], "udp") && (iArgC >= 12)) {
+ fcentry.fc_proto = IPPROTO_UDP;
+ iBuf = 12;
+
+ } else {
+ goto __arg_error;
+ }
+
+ if (!inet_aton(ppcArgV[3], &((struct sockaddr_in *)&fcentry.fc_start)->sin_addr)) {
+ goto __arg_error;
+ }
+
+ if (!inet_aton(ppcArgV[4], &((struct sockaddr_in *)&fcentry.fc_end)->sin_addr)) {
+ goto __arg_error;
+ }
+
+ if (fcentry.fc_proto) {
+ if (sscanf(ppcArgV[6], "%d", &iSPort) != 1) {
+ goto __arg_error;
+ }
+
+ if (sscanf(ppcArgV[7], "%d", &iEPort) != 1) {
+ goto __arg_error;
+ }
+
+ fcentry.fc_sport = htons(iSPort);
+ fcentry.fc_eport = htons(iEPort);
+
+ iIndex = 9;
+
+ } else {
+ iIndex = 7;
+ }
+
+ lib_strlcpy(fcentry.fc_ifname, ppcArgV[iIndex], IF_NAMESIZE);
+ iIndex++;
+
+ if (sscanf(ppcArgV[iIndex], "%qu", &fcentry.fc_uprate) != 1) {
+ goto __arg_error;
+ }
+ iIndex++;
+
+ if (sscanf(ppcArgV[iIndex], "%qu", &fcentry.fc_downrate) != 1) {
+ goto __arg_error;
+ }
+ iIndex++;
+
+ if (iArgC > iBuf) {
+ if (sscanf(ppcArgV[iIndex], "%zu", &stBufSize) != 1) {
+ goto __arg_error;
+ }
+ }
+
+ fcentry.fc_uprate <<= 10;
+ fcentry.fc_downrate <<= 10;
+ fcentry.fc_bufsize = (stBufSize << 10);
+
+ iSock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (iSock < 0) {
+ fprintf(stderr, "can not create socket error: %s!\n", lib_strerror(errno));
+ return (PX_ERROR);
+ }
+
+ iRet = ioctl(iSock, SIOCADDFC, &fcentry);
+ if (iRet < 0) {
+ fprintf(stderr, "command 'SIOCADDFC' error: %s!\n", lib_strerror(errno));
+ close(iSock);
+ return (PX_ERROR);
+ }
+ close(iSock);
+
+ return (ERROR_NONE);
+}
+/*********************************************************************************************************
+** 函数名称: __fc_delete_if
+** 功能描述: 删除网络接口流控信息
+** 输 入 : iArgC 参数个数
+** ppcArgV 参数表
+** 输 出 : ERROR
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static INT __fc_delete_if (INT iArgC, PCHAR *ppcArgV)
+{
+ INT iRet;
+ INT iSock;
+ struct fcentry fcentry;
+
+ lib_bzero(&fcentry, sizeof(struct fcentry));
+ fcentry.fc_type = FCT_IF;
+ fcentry.fc_enable = 1;
+
+ if ((iArgC < 5) && lib_strcmp(ppcArgV[3], "dev")) {
+ fprintf(stderr, "arguments error!\n");
+ return (-ERROR_TSHELL_EPARAM);
+ }
+
+ lib_strlcpy(fcentry.fc_ifname, ppcArgV[4], IF_NAMESIZE);
+
+ iSock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (iSock < 0) {
+ fprintf(stderr, "can not create socket error: %s!\n", lib_strerror(errno));
+ return (PX_ERROR);
+ }
+
+ iRet = ioctl(iSock, SIOCDELFC, &fcentry);
+ if (iRet < 0) {
+ fprintf(stderr, "command 'SIOCDELFC' error: %s!\n", lib_strerror(errno));
+ close(iSock);
+ return (PX_ERROR);
+ }
+ close(iSock);
+
+ return (ERROR_NONE);
+}
+/*********************************************************************************************************
+** 函数名称: __fc_delete_ip
+** 功能描述: 删除 IPv4 流控信息
+** 输 入 : iArgC 参数个数
+** ppcArgV 参数表
+** 输 出 : ERROR
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static INT __fc_delete_ip (INT iArgC, PCHAR *ppcArgV)
+{
+ INT iRet, iIndex;
+ INT iSPort, iEPort;
+ INT iSock;
+ struct fcentry fcentry;
+
+ lib_bzero(&fcentry, sizeof(struct fcentry));
+ fcentry.fc_type = FCT_IP;
+ fcentry.fc_enable = 1;
+
+ if (iArgC < 8) {
+__arg_error:
+ fprintf(stderr, "arguments error!\n");
+ return (-ERROR_TSHELL_EPARAM);
+ }
+
+ if (!lib_strcmp(ppcArgV[5], "all")) {
+ fcentry.fc_proto = 0;
+
+ } else if (!lib_strcmp(ppcArgV[5], "tcp") && (iArgC >= 10)) {
+ fcentry.fc_proto = IPPROTO_TCP;
+
+ } else if (!lib_strcmp(ppcArgV[5], "udp") && (iArgC >= 10)) {
+ fcentry.fc_proto = IPPROTO_UDP;
+
+ } else {
+ goto __arg_error;
+ }
+
+ if (!inet_aton(ppcArgV[3], &((struct sockaddr_in *)&fcentry.fc_start)->sin_addr)) {
+ goto __arg_error;
+ }
+
+ if (!inet_aton(ppcArgV[4], &((struct sockaddr_in *)&fcentry.fc_end)->sin_addr)) {
+ goto __arg_error;
+ }
+
+ if (fcentry.fc_proto) {
+ if (sscanf(ppcArgV[6], "%d", &iSPort) != 1) {
+ goto __arg_error;
+ }
+
+ if (sscanf(ppcArgV[7], "%d", &iEPort) != 1) {
+ goto __arg_error;
+ }
+
+ fcentry.fc_sport = htons(iSPort);
+ fcentry.fc_eport = htons(iEPort);
+
+ iIndex = 9;
+
+ } else {
+ iIndex = 7;
+ }
+
+ lib_strlcpy(fcentry.fc_ifname, ppcArgV[iIndex], IF_NAMESIZE);
+
+ iSock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (iSock < 0) {
+ fprintf(stderr, "can not create socket error: %s!\n", lib_strerror(errno));
+ return (PX_ERROR);
+ }
+
+ iRet = ioctl(iSock, SIOCDELFC, &fcentry);
+ if (iRet < 0) {
+ fprintf(stderr, "command 'SIOCDELFC' error: %s!\n", lib_strerror(errno));
+ close(iSock);
+ return (PX_ERROR);
+ }
+ close(iSock);
+
+ return (ERROR_NONE);
+}
+/*********************************************************************************************************
+** 函数名称: __fc_change_if
+** 功能描述: 修改网络接口流控信息
+** 输 入 : iArgC 参数个数
+** ppcArgV 参数表
+** 输 出 : ERROR
+** 全局变量:
+** 调用模块:
+*********************************************************************************************************/
+static INT __fc_change_if (INT iArgC, PCHAR *ppcArgV)
+{
+ INT iRet;
+ INT iSock;
+ struct fcentry fcentry;
+ size_t stBufSize = FC_DEFAULT_BUF_SIZE_KB;
+
+ lib_bzero(&fcentry, sizeof(struct fcentry));
+ fcentry.fc_type = FCT_IF;
+ fcentry.fc_enable = 1;
+
+ if ((iArgC < 7) || lib_strcmp(ppcArgV[3], "dev")) {
+__arg_error:
+ fprintf(stderr, "arguments error!\n");
+ return (-ERROR_TSHELL_EPARAM);
+ }
+
+ lib_strlcpy(fcentry.fc_ifname, ppcArgV[4], IF_NAMESIZE);
+
+ if (sscanf(ppcArgV[5], "%qu", &fcentry.fc_uprate) != 1) {
+ goto __arg_error;
+ }
+
+ if (sscanf(ppcArgV[6], "%qu", &fcentry.fc_downrate) != 1) {
+ goto __arg_error;
+ }
+
+ if (iArgC > 7) {
+ if (sscanf(ppcArgV[6], "%zu", &stBufSize) != 1) {
+ goto __arg_error;
+ }
+ }
+
+ fcentry.fc_uprate <<= 10;
+ fcentry.fc_downrate <<= 10;
+ fcentry.fc_bufsize = (stBufSize << 10);
+
+ iSock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (iSock < 0) {
+ fprintf(stderr, "can not create socket error: %s!\n", lib_strerror(errno));
+ return (PX_ERROR);
+ }
+
+ iRet = ioctl(iSock, SIOCCHGFC, &fcentry);
+ if (iRet < 0) {
+ fprintf(stderr, "command 'SIOCCHGFC' error: %s!\n", lib_strerror(errno));
+ close(iSock);
+ return (PX_ERROR);
+ }
+ close(iSock);
+
+ return (ERROR_NONE);
+}
+/*******************************************************************************************